diff --git a/DEPS b/DEPS index 6478d08..53286b0 100644 --- a/DEPS +++ b/DEPS
@@ -239,7 +239,7 @@ # luci-go CIPD package version. # Make sure the revision is uploaded by infra-packagers builder. # https://ci.chromium.org/p/infra-internal/g/infra-packagers/console - 'luci_go': 'git_revision:0250323d999386415553b5e2297eafe827ca41f3', + 'luci_go': 'git_revision:b0488766ec2a119f97c0189ffa5fff13e4da0131', # This can be overridden, e.g. with custom_vars, to build clang from HEAD # instead of downloading the prebuilt pinned revision. @@ -298,11 +298,11 @@ # 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': '5110982b4020c8303ab7aece58818cb7eaee972e', + 'v8_revision': 'c59f2d912981432362352d6ae5620726d41a85cb', # 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': 'cb432540e120916a9f503be74d128be74ec2ae8e', + 'angle_revision': '3b7528e1c70f8cbe5643d91e3647a502a348e29f', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -402,7 +402,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': '5602ae03628ac1ae4ba8d265ac1979abea42d6ba', + 'dawn_revision': '56724d23899220ea9a775b4ab4458e6ebc53ad52', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -506,7 +506,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling llvm-libc # and whatever else without interference from each other. - 'llvm_libc_revision': 'e09972e0948f01cace57c08ba82b61fc171c739c', + 'llvm_libc_revision': '79a5aa1b7fcbdf3397bc2a08cbd6ef5c302dfb5a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling llvm-libc # and whatever else without interference from each other. @@ -1563,7 +1563,7 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - '87688db09fa1af75f935e82e11b7e21594f2c443', + '4730f3cb56f9907131c3de8b318b4300b39d3e3d', 'condition': 'checkout_android and checkout_src_internal', }, @@ -1717,7 +1717,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': 'KPzBB78zNuKqVngFFr_rnzJbD3nyMR3Bo83oqlKTcDAC', + 'version': 'paQ7h7FTQKWOd-p_4_zJ-R9frQx5tWzXg05pnk8rlOgC', }, ], 'condition': 'checkout_android and non_git_source', @@ -1810,7 +1810,7 @@ 'packages': [ { 'package': 'chromium/third_party/android_build_tools/lint', - 'version': 'Ddt_nMFT2APf615MrUZPaZpe-MqZSNrJmk8s9ud-f3gC', + 'version': 'RevkTwhOQRk-oOzI4BBk3FYEeVAlBijeTqjNPrGsi_8C', }, ], 'condition': 'checkout_android and non_git_source', @@ -1821,7 +1821,7 @@ 'packages': [ { 'package': 'chromium/third_party/android_build_tools/manifest_merger', - 'version': 'JcTHGCKOl5tWhax5LSv_vf5dQV14RZdPF9xSRKU76JgC', + 'version': 'v0s5-TwZ9OxfzbqU5ULhQ7vufSuKIIld6Z7TK8artzoC', }, ], 'condition': 'checkout_android and non_git_source', @@ -2593,7 +2593,7 @@ Var('pdfium_git') + '/pdfium.git' + '@' + Var('pdfium_revision'), 'src/third_party/perfetto': - Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + '21d660f5550822d7bcf79c43595ffbf258fe681a', + Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + 'cca1748cb16b9dc0cac21515813c3855a983917d', 'src/base/tracing/test/data': { 'bucket': 'perfetto', @@ -2912,15 +2912,15 @@ 'dep_type': 'cipd', }, - 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@565c281d73214e4712bd78be4cb7ccc2833ea471', + 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@49cfa5309d365d4ea40bd92b399595c30d8dc96e', 'src/third_party/glslang/src': '{chromium_git}/external/github.com/KhronosGroup/glslang@21b4e37133868b3a50ef15fc027ecd6d3a52c875', '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@2a611a970fdbc41ac2e3e328802aed9985352dca', - 'src/third_party/spirv-tools/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Tools@85607567adde930f1598024116caa1ff9831848c', + 'src/third_party/spirv-tools/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Tools@108b19e5c6979f496deffad4acbe354237afa7d3', 'src/third_party/vulkan-headers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Headers@10739e8e00a7b6f74d22dd0a547f1406ff1f5eb9', - 'src/third_party/vulkan-loader/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Loader@dc6786e527cf8cefd244318f546b3b2ec26e84f4', - 'src/third_party/vulkan-tools/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Tools@d671923090e4dc74c0ebdb10c6e09fa0826e1fe9', - 'src/third_party/vulkan-utility-libraries/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Utility-Libraries@54c9baf20802a13279e23fa4cb0528dd5cf16064', + 'src/third_party/vulkan-loader/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Loader@c8a2c8c9164a58ce71c1c77104e28e8de724539e', + 'src/third_party/vulkan-tools/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Tools@e3fc64396755191b3c51e5c57d0454872e7fa487', + 'src/third_party/vulkan-utility-libraries/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Utility-Libraries@0f0babb553a60da5971d9f4d40cf720ce01602f1', 'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@d9c0a0baa0d2c7357d464d73a6fcee76f970c39b', 'src/third_party/vulkan_memory_allocator': @@ -3170,7 +3170,7 @@ 'packages': [ { 'package': 'chromium/third_party/android_deps/autorolled', - 'version': 'wwEVy7_RC0x_RaBvdiHlg6X_Hu-pwMbiNF3_gX_zCAAC', + 'version': '3Z0aCsA0SPsomTmXpIXuoQD9PxvOKH1lF3B8tv_v32gC', }, ], 'condition': 'checkout_android and non_git_source', @@ -4686,7 +4686,7 @@ 'src/components/optimization_guide/internal': { 'url': Var('chrome_git') + '/chrome/components/optimization_guide.git' + '@' + - '9e8ee5114eb95c9675a3ea819e20773bc26e760c', + '3c89dd68e24fda4ce1dad3c9ee0c9441059f7fb0', 'condition': 'checkout_src_internal', }, @@ -4752,7 +4752,7 @@ 'src/ios_internal': { 'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' + - 'cd9acb0b818968f4583555dbb6ecf12a388fafbc', + 'b8a110660c3ff24ecb3358f24baf562ceca2b41c', '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 67d8923..8fd1812 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
@@ -208,6 +208,9 @@ Flag.baseFeature( BlinkFeatures.LAYOUT_NG_SHAPE_CACHE, "Cache shape results for short text blocks."), Flag.baseFeature( + BlinkFeatures.FORCE_OFF_TEXT_AUTOSIZING, + "Disable text inflation with setLayoutAlgorithm(TEXT_AUTOSIZING)"), + Flag.baseFeature( NetFeatures.SIMDUTF_BASE64_SUPPORT, "Use the simdutf library to base64 decode data: URLs."), Flag.baseFeature(
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc index a3156b3..216caab2 100644 --- a/ash/constants/ash_features.cc +++ b/ash/constants/ash_features.cc
@@ -2625,7 +2625,7 @@ // Enables sea pen text input feature in the personalization app. BASE_FEATURE(kSeaPenTextInput, "SeaPenTextInput", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); // Enables sea pen text input translation feature. BASE_FEATURE(kSeaPenTextInputTranslation,
diff --git a/ash/system/toast/system_nudge_view.cc b/ash/system/toast/system_nudge_view.cc index 3507057..c85c3d8 100644 --- a/ash/system/toast/system_nudge_view.cc +++ b/ash/system/toast/system_nudge_view.cc
@@ -449,11 +449,11 @@ void SystemNudgeView::AddedToWidget() { GetWidget()->AddObserver(this); - // Attach the shadow at the bottom of the widget layer. + // Attach the shadow at the bottom of the parent layer. auto* shadow_layer = shadow_->GetLayer(); - auto* widget_layer = GetWidget()->GetLayer(); - widget_layer->Add(shadow_layer); - widget_layer->StackAtBottom(shadow_layer); + auto* parent_layer = layer()->parent(); + parent_layer->Add(shadow_layer); + parent_layer->StackAtBottom(shadow_layer); } void SystemNudgeView::RemovedFromWidget() {
diff --git a/ash/webui/common/resources/sea_pen/sea_pen_image_loading_element.html b/ash/webui/common/resources/sea_pen/sea_pen_image_loading_element.html index 32503c1..f14c9b4 100644 --- a/ash/webui/common/resources/sea_pen/sea_pen_image_loading_element.html +++ b/ash/webui/common/resources/sea_pen/sea_pen_image_loading_element.html
@@ -7,13 +7,14 @@ display: flex; flex-direction: row; gap: 10px; - height: 32px; justify-content: center; + min-height: 32px; padding-inline: 14px; } paper-spinner-lite { --paper-spinner-color: var(--cros-button-label-color-primary-disabled); + flex-shrink: 0; height: 20px; width: 20px; }
diff --git a/ash/webui/common/resources/sea_pen/sea_pen_input_query_element.ts b/ash/webui/common/resources/sea_pen/sea_pen_input_query_element.ts index 6587e803..1fc668c 100644 --- a/ash/webui/common/resources/sea_pen/sea_pen_input_query_element.ts +++ b/ash/webui/common/resources/sea_pen/sea_pen_input_query_element.ts
@@ -186,7 +186,8 @@ this.textValue_ = e.detail; this.showCreateButton_(); this.focusInput_(); - if (e.type === SeaPenSampleSelectedEvent.EVENT_NAME) { + if (e.type === SeaPenSampleSelectedEvent.EVENT_NAME && + !this.thumbnailsLoading_) { this.searchInputQuery_(); } }
diff --git a/base/metrics/crc32.cc b/base/metrics/crc32.cc index 83e3cee2..54f43bf5 100644 --- a/base/metrics/crc32.cc +++ b/base/metrics/crc32.cc
@@ -3,14 +3,10 @@ // found in the LICENSE file. #include "base/metrics/crc32.h" - -#if !BUILDFLAG(IS_NACL) #include "third_party/zlib/zlib.h" -#endif // !BUILDFLAG(IS_NACL) namespace base { -#if !BUILDFLAG(IS_NACL) uint32_t Crc32(uint32_t sum, span<const uint8_t> data) { if (data.empty()) { return sum; @@ -28,77 +24,5 @@ return static_cast<uint32_t>( (~crc32_z((~sum) & 0xffffffff, data.data(), data.size())) & 0xffffffff); } -#else -// Static table of checksums for all possible 8 bit bytes. -static constexpr std::array<uint32_t, 256> kCrcTable = { - 0x0, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x76dc419L, - 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0xedb8832L, 0x79dcb8a4L, - 0xe0d5e91eL, 0x97d2d988L, 0x9b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, - 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, - 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, - 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, - 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, - 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, - 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, - 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, - 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, - 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, - 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, - 0x1db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x6b6b51fL, - 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0xf00f934L, 0x9609a88eL, - 0xe10e9818L, 0x7f6a0dbbL, 0x86d3d2dL, 0x91646c97L, 0xe6635c01L, - 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, - 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, - 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, - 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, - 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, - 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, - 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, - 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, - 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, - 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, - 0x3b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x4db2615L, - 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0xd6d6a3eL, 0x7a6a5aa8L, - 0xe40ecf0bL, 0x9309ff9dL, 0xa00ae27L, 0x7d079eb1L, 0xf00f9344L, - 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, - 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, - 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, - 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, - 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, - 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, - 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, - 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, - 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, - 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, - 0x26d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x5005713L, - 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0xcb61b38L, 0x92d28e9bL, - 0xe5d5be0dL, 0x7cdcefb7L, 0xbdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, - 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, - 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, - 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, - 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, - 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, - 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, - 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, - 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, - 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, - 0x2d02ef8dL, -}; - -// We generate the CRC-32 using the low order bits to select whether to XOR in -// the reversed polynomial 0xEDB88320. This is nice and simple, and allows us -// to keep the quotient in a uint32_t. Since we're not concerned about the -// nature of corruptions (i.e., we don't care about bit sequencing, since we are -// handling memory changes, which are more grotesque) so we don't bother to get -// the CRC correct for big-endian vs little-ending calculations. All we need is -// a nice hash, that tends to depend on all the bits of the sample, with very -// little chance of changes in one place impacting changes in another place. -uint32_t Crc32(uint32_t sum, span<const uint8_t> data) { - for (uint8_t byte : data) { - sum = kCrcTable[(sum & 0x000000FF) ^ byte] ^ (sum >> 8); - } - return sum; -} -#endif // !BUILDFLAG(IS_NACL) } // namespace base
diff --git a/build/android/gyp/aidl.py b/build/android/gyp/aidl.py index 6bb593a..7b2ea94 100755 --- a/build/android/gyp/aidl.py +++ b/build/android/gyp/aidl.py
@@ -7,7 +7,7 @@ """Invokes Android's aidl """ -import optparse +import argparse import os import re import sys @@ -39,19 +39,21 @@ def main(argv): - option_parser = optparse.OptionParser() - option_parser.add_option('--aidl-path', help='Path to the aidl binary.') - option_parser.add_option('--imports', help='Files to import.') - option_parser.add_option('--header-output-dir', - help='Optional header file output location.') - option_parser.add_option('--cpp-output', - help='Optional cpp file output location.', - action='append') - option_parser.add_option('--includes', - help='Directories to add as import search paths.') - option_parser.add_option('--srcjar', help='Path for srcjar output.') - action_helpers.add_depfile_arg(option_parser) - options, args = option_parser.parse_args(argv[1:]) + parser = argparse.ArgumentParser() + parser.add_argument('--aidl-path', help='Path to the aidl binary.') + parser.add_argument('--imports', help='Files to import.') + parser.add_argument('--header-output-dir', + help='Optional header file output location.') + parser.add_argument('--cpp-output', + help='Optional cpp file output location.', + action='append') + parser.add_argument('--includes', + help='Directories to add as import search paths.') + parser.add_argument('--srcjar', help='Path for srcjar output.') + parser.add_argument('files', nargs='+') + action_helpers.add_depfile_arg(parser) + options = parser.parse_args(argv[1:]) + args = options.files options.includes = action_helpers.parse_gn_list(options.includes)
diff --git a/build/android/gyp/copy_ex.py b/build/android/gyp/copy_ex.py index 542a08c..505357f 100755 --- a/build/android/gyp/copy_ex.py +++ b/build/android/gyp/copy_ex.py
@@ -7,9 +7,9 @@ """Copies files to a directory.""" +import argparse import filecmp import itertools -import optparse import os import shutil import sys @@ -86,27 +86,28 @@ def main(args): args = build_utils.ExpandFileArgs(args) - parser = optparse.OptionParser() + parser = argparse.ArgumentParser() action_helpers.add_depfile_arg(parser) - parser.add_option('--dest', help='Directory to copy files to.') - parser.add_option('--files', action='append', - help='List of files to copy.') - parser.add_option('--clear', action='store_true', - help='If set, the destination directory will be deleted ' - 'before copying files to it. This is highly recommended to ' - 'ensure that no stale files are left in the directory.') - parser.add_option('--stamp', help='Path to touch on success.') - parser.add_option('--renaming-sources', - action='append', - help='List of files need to be renamed while being ' - 'copied to dest directory') - parser.add_option('--renaming-destinations', - action='append', - help='List of destination file name without path, the ' - 'number of elements must match rename-sources.') + parser.add_argument('--dest', help='Directory to copy files to.') + parser.add_argument('--files', action='append', help='List of files to copy.') + parser.add_argument( + '--clear', + action='store_true', + help='If set, the destination directory will be deleted ' + 'before copying files to it. This is highly recommended to ' + 'ensure that no stale files are left in the directory.') + parser.add_argument('--stamp', help='Path to touch on success.') + parser.add_argument('--renaming-sources', + action='append', + help='List of files need to be renamed while being ' + 'copied to dest directory') + parser.add_argument('--renaming-destinations', + action='append', + help='List of destination file name without path, the ' + 'number of elements must match rename-sources.') - options, _ = parser.parse_args(args) + options = parser.parse_args(args) if options.clear: build_utils.DeleteDirectory(options.dest)
diff --git a/build/android/gyp/extract_unwind_tables_tests.py b/build/android/gyp/extract_unwind_tables_tests.py index 1690798..143ab06 100755 --- a/build/android/gyp/extract_unwind_tables_tests.py +++ b/build/android/gyp/extract_unwind_tables_tests.py
@@ -10,7 +10,6 @@ """ import io -import optparse import os import struct import sys
diff --git a/build/android/gyp/java_cpp_enum.py b/build/android/gyp/java_cpp_enum.py index 66ea639d..98d6365 100755 --- a/build/android/gyp/java_cpp_enum.py +++ b/build/android/gyp/java_cpp_enum.py
@@ -4,10 +4,10 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import argparse import collections from datetime import date import re -import optparse import os from string import Template import sys @@ -490,22 +490,20 @@ def DoMain(argv): - usage = 'usage: %prog [options] [output_dir] input_file(s)...' - parser = optparse.OptionParser(usage=usage) + parser = argparse.ArgumentParser() - parser.add_option('--srcjar', - help='When specified, a .srcjar at the given path is ' - 'created instead of individual .java files.') + parser.add_argument('--srcjar', + help='When specified, a .srcjar at the given path is ' + 'created instead of individual .java files.') + parser.add_argument('input_paths', + nargs='+', + help='Path to at least one input file.') - options, args = parser.parse_args(argv) - - if not args: - parser.error('Need to specify at least one input file') - input_paths = args + options = parser.parse_args(argv) with action_helpers.atomic_output(options.srcjar) as f: with zipfile.ZipFile(f, 'w', zipfile.ZIP_STORED) as srcjar: - for output_path, data in DoGenerate(input_paths): + for output_path, data in DoGenerate(options.input_paths): zip_helpers.add_to_zip_hermetic(srcjar, output_path, data=data)
diff --git a/build/android/gyp/process_native_prebuilt.py b/build/android/gyp/process_native_prebuilt.py index 060adae8..7e4a708e 100755 --- a/build/android/gyp/process_native_prebuilt.py +++ b/build/android/gyp/process_native_prebuilt.py
@@ -27,9 +27,11 @@ with action_helpers.atomic_output(options.stripped_output_path) as out: cmd = [ options.strip_path, - options.input_path, + '--strip-debug', + '--strip-unneeded', '-o', out.name, + options.input_path, ] build_utils.CheckOutput(cmd) shutil.copyfile(options.input_path, options.unstripped_output_path)
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni index c7c8d492..9a8b9a3d 100644 --- a/build/config/android/rules.gni +++ b/build/config/android/rules.gni
@@ -637,7 +637,13 @@ _stripped_output_path = "$root_out_dir/${invoker.lib_name}" _unstripped_output_path = "$root_out_dir/lib.unstripped/${invoker.lib_name}" - inputs = [ _lib_path ] + inputs = [ + _lib_path, + "${clang_base_path}/bin/llvm-strip", + + # llvm-objcopy is required since llvm-strip symlinks to it. + "${clang_base_path}/bin/llvm-objcopy", + ] outputs = [ _stripped_output_path, _unstripped_output_path, @@ -653,8 +659,7 @@ _rebased_unstripped_ouput_path = rebase_path(_unstripped_output_path, root_build_dir) _strip_tool_path = - rebase_path("//buildtools/third_party/eu-strip/bin/eu-strip", - root_build_dir) + rebase_path("${clang_base_path}/bin/llvm-strip", root_build_dir) args = [ "--strip-path=$_strip_tool_path",
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index 994f9c2..0c04c90 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn
@@ -2161,7 +2161,7 @@ ] } - if (is_component_build && use_clang_warning_suppression_file) { + if (is_component_build && use_clang_warning_suppression_file && !is_win) { # Warn for globally unique objects which might get duplicated if built # into different components, due to hidden visibility. Only applicable # to component builds.
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinator.java index ce27bd8..9d49e54 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinator.java
@@ -86,6 +86,7 @@ import org.chromium.components.tab_group_sync.TabGroupSyncService; import org.chromium.components.tab_group_sync.TabGroupUiActionHandler; import org.chromium.components.tab_group_sync.TriggerSource; +import org.chromium.ui.base.LocalizationUtils; import org.chromium.ui.interpolators.Interpolators; import org.chromium.ui.modaldialog.ModalDialogManager; import org.chromium.ui.modelutil.LayoutViewBuilder; @@ -635,8 +636,11 @@ mDialogView.post( () -> { + int dialogViewWidth = mDialogView.getWidth(); + int translationFactor = + LocalizationUtils.isLayoutRtl() ? -dialogViewWidth : dialogViewWidth; mDialogView.setVisibility(View.VISIBLE); - mDialogView.setTranslationX(mDialogView.getWidth()); + mDialogView.setTranslationX(translationFactor); AnimatorSet animatorSet = new AnimatorSet(); animatorSet.setDuration(duration); @@ -648,14 +652,15 @@ } private List<Animator> getAnimateInAnimators() { + int tabSwitcherViewWidth = mTabSwitcherView.getWidth(); + int translationFactor = + LocalizationUtils.isLayoutRtl() ? tabSwitcherViewWidth : -tabSwitcherViewWidth; List<Animator> animators = new ArrayList<>(2); ObjectAnimator animator = ObjectAnimator.ofFloat(mDialogView, View.TRANSLATION_X, 0f); animator.setInterpolator(Interpolators.ACCELERATE_INTERPOLATOR); animators.add(animator); - animator = - ObjectAnimator.ofFloat( - mTabSwitcherView, View.TRANSLATION_X, -mTabSwitcherView.getWidth()); + animator = ObjectAnimator.ofFloat(mTabSwitcherView, View.TRANSLATION_X, translationFactor); animator.setInterpolator(Interpolators.ACCELERATE_INTERPOLATOR); animators.add(animator); @@ -682,9 +687,12 @@ } private List<Animator> getAnimateOutAnimators() { + int dialogViewWidth = mDialogView.getWidth(); + int translationFactor = + LocalizationUtils.isLayoutRtl() ? -dialogViewWidth : dialogViewWidth; List<Animator> animators = new ArrayList<>(2); ObjectAnimator animator = - ObjectAnimator.ofFloat(mDialogView, View.TRANSLATION_X, mDialogView.getWidth()); + ObjectAnimator.ofFloat(mDialogView, View.TRANSLATION_X, translationFactor); animator.setInterpolator(Interpolators.ACCELERATE_INTERPOLATOR); animators.add(animator);
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorToolbar.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorToolbar.java index a807d68..b35ea51 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorToolbar.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorToolbar.java
@@ -98,6 +98,7 @@ final @ColorInt int lightIconColor = SemanticColorUtils.getDefaultIconColorInverse(getContext()); navigationIconDrawable.setTint(lightIconColor); + navigationIconDrawable.setAutoMirrored(true); setNavigationIcon(navigationIconDrawable); setNavigationContentDescription(mBackButtonAccessibilityString);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java index e390edd..cdd2e77c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -2610,7 +2610,7 @@ new TabbedSystemBarColorHelper( ensureEdgeToEdgeLayoutCoordinator(), mBottomChinSupplier)); return mSystemBarColorHelperSupplier; - } else if (EdgeToEdgeUtils.isEdgeToEdgeBottomChinEnabled(this)) { + } else if (EdgeToEdgeUtils.isBottomChinFeatureEnabled()) { // If isEdgeToEdgeBottomChinEnabled() && !isEdgeToEdgeEverywhereEnabled() return mBottomChinSupplier; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java index 972a65c..5cf2ac98 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
@@ -325,6 +325,12 @@ mLocationBar.onNativeLibraryReady(); } + /** Returns the incognito image view. */ + @Nullable + ImageView getIncognitoImageView() { + return mIncognitoImageView; + } + /** Returns the incognito image view, inflating it first if necessary. */ ImageView ensureIncognitoImageViewInflated() { if (mIncognitoImageView != null) { @@ -585,10 +591,19 @@ @Override protected void updateCustomActionButton(int index, Drawable drawable, String description) { - // |index| -> childIndex should ignore the optional button always present at the end. - int childIndex = mCustomActionButtons.getChildCount() - 2 - index; - assert 0 <= childIndex && childIndex <= mCustomActionButtons.getChildCount() - 2; - ImageButton button = (ImageButton) mCustomActionButtons.getChildAt(childIndex); + ImageButton button; + + if (ChromeFeatureList.sCctToolbarRefactor.isEnabled()) { + button = + (ImageButton) + mCustomButtonsParent.getChildAt( + mCustomButtonsParent.getChildCount() - 1 - index); + } else { + // |index| -> childIndex should ignore the optional button always present at the end. + int childIndex = mCustomActionButtons.getChildCount() - 2 - index; + assert 0 <= childIndex && childIndex <= mCustomActionButtons.getChildCount() - 2; + button = (ImageButton) mCustomActionButtons.getChildAt(childIndex); + } assert button != null; updateCustomActionButtonVisuals(button, drawable, description); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsProperties.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsProperties.java index 654a7fb..4d06baa 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsProperties.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsProperties.java
@@ -151,7 +151,7 @@ public static final ReadableBooleanPropertyKey TITLE_VISIBLE = new ReadableBooleanPropertyKey(); /** Property key for whether the CCT is incognito. */ - public static final ReadableBooleanPropertyKey IS_INCOGNITO = new ReadableBooleanPropertyKey(); + public static final WritableBooleanPropertyKey IS_INCOGNITO = new WritableBooleanPropertyKey(); public static PropertyModel create( boolean customActionButtonsVisible,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31.java b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31.java index fa063bb..c64d4292 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.multiwindow; +import static org.chromium.build.NullUtil.assertNonNull; import static org.chromium.build.NullUtil.assumeNonNull; import static org.chromium.chrome.browser.tabwindow.TabWindowManager.INVALID_WINDOW_ID; @@ -76,14 +77,17 @@ import org.chromium.components.favicon.LargeIconBridge; import org.chromium.components.feature_engagement.EventConstants; import org.chromium.components.feature_engagement.Tracker; +import org.chromium.components.messages.MessageDispatcher; import org.chromium.components.tab_group_sync.TabGroupSyncService; import org.chromium.ui.modaldialog.ModalDialogManager; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeMap; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -138,25 +142,24 @@ mModalDialogManagerSupplier = modalDialogManagerSupplier; mDesktopWindowStateManagerSupplier = desktopWindowStateManagerSupplier; mOnMultiInstanceStateChanged = this::onMultiInstanceStateChanged; + + // Check if instance limit has changed and update SharedPrefs. + SharedPreferencesManager prefs = ChromeSharedPreferences.getInstance(); + int prevInstanceLimit = + prefs.readInt( + ChromePreferenceKeys.MULTI_INSTANCE_MAX_INSTANCE_LIMIT, mMaxInstances); + if (mMaxInstances > prevInstanceLimit) { + // Reset SharedPref for instance limit downgrade if limit has increased. + prefs.writeBoolean( + ChromePreferenceKeys.MULTI_INSTANCE_INSTANCE_LIMIT_DOWNGRADE_TRIGGERED, false); + } + prefs.writeInt(ChromePreferenceKeys.MULTI_INSTANCE_MAX_INSTANCE_LIMIT, mMaxInstances); } @Override public boolean handleMenuOrKeyboardAction(int id, boolean fromMenu) { if (id == org.chromium.chrome.R.id.manage_all_windows_menu_id) { - List<InstanceInfo> info = getInstanceInfo(); - InstanceSwitcherCoordinator.showDialog( - mActivity, - mModalDialogManagerSupplier.get(), - new LargeIconBridge(getProfile()), - (item) -> openInstance(item.instanceId, item.taskId), - (item) -> { - RecordUserAction.record("MobileMenuWindowManagerCloseInstance"); - closeInstance(item.instanceId, item.taskId); - cleanupSyncedTabGroupsIfLastInstance(); - }, - () -> openNewWindow("Android.WindowManager.NewWindow"), - MultiWindowUtils.getMaxInstances(), - info); + showInstanceSwitcherDialog(); if (AppHeaderUtils.isAppInDesktopWindow(mDesktopWindowStateManagerSupplier.get())) { RecordUserAction.record("MobileMenuWindowManager.InDesktopWindow"); @@ -176,6 +179,23 @@ return super.handleMenuOrKeyboardAction(id, fromMenu); } + private void showInstanceSwitcherDialog() { + List<InstanceInfo> info = getInstanceInfo(); + InstanceSwitcherCoordinator.showDialog( + mActivity, + mModalDialogManagerSupplier.get(), + new LargeIconBridge(getProfile()), + (item) -> openInstance(item.instanceId, item.taskId), + (item) -> { + RecordUserAction.record("MobileMenuWindowManagerCloseInstance"); + closeInstance(item.instanceId, item.taskId); + cleanupSyncedTabGroupsIfLastInstance(); + }, + () -> openNewWindow("Android.WindowManager.NewWindow"), + MultiWindowUtils.getMaxInstances(), + info); + } + @Override public void moveTabToOtherWindow(Tab tab) { if (MultiWindowUtils.getInstanceCount() == 1) { @@ -456,6 +476,8 @@ @Override public Pair<Integer, Integer> allocInstanceId(int windowId, int taskId, boolean preferNew) { removeInvalidInstanceData(/* cleanupApplicationStatus= */ true); + // Finish excess running activities / tasks after an instance limit downgrade. + finishExcessRunningActivities(); int instanceId = getInstanceByTask(taskId); @@ -521,6 +543,57 @@ return Pair.create(id, allocationType); } + // This method will finish the least recently used excess running activities / tasks exactly + // once after an instance limit downgrade. + private void finishExcessRunningActivities() { + SharedPreferencesManager prefs = ChromeSharedPreferences.getInstance(); + // Return early if an instance limit downgrade has been handled previously. This is to avoid + // a case where we end up replacing an active instance with a newly created activity (by + // finishing the task for the former) when max instances are open. + if (prefs.readBoolean( + ChromePreferenceKeys.MULTI_INSTANCE_INSTANCE_LIMIT_DOWNGRADE_TRIGGERED, false)) { + return; + } + + Set<Integer> instanceIds = getPersistedInstanceIds(); + int numTasksToFinish = instanceIds.size() - MultiWindowUtils.getMaxInstances(); + if (numTasksToFinish <= 0) return; + + prefs.writeBoolean( + ChromePreferenceKeys.MULTI_INSTANCE_INSTANCE_LIMIT_DOWNGRADE_TRIGGERED, true); + + // Get the instance ids of up to |numTasksToFinish| least recently used instances. + TreeMap<Long, Integer> lruInstanceIds = new TreeMap<>(); + for (int i : instanceIds) { + if (getTaskFromMap(i) == INVALID_TASK_ID) continue; + long lastAccessedTime = readLastAccessedTime(i); + lruInstanceIds.put(lastAccessedTime, i); + if (lruInstanceIds.size() > numTasksToFinish) { + lruInstanceIds.remove(lruInstanceIds.lastKey()); + } + } + + // Determine the active tasks that need to be finished. + Map<Integer, Integer> tasksToDelete = new HashMap<>(); + for (Integer i : lruInstanceIds.values()) { + tasksToDelete.put(getTaskFromMap(i), i); + } + + // Finish AppTasks that are excess of what is required to stay within the instance limit. + List<AppTask> appTasks = + ((ActivityManager) mActivity.getSystemService(Context.ACTIVITY_SERVICE)) + .getAppTasks(); + for (AppTask appTask : appTasks) { + var taskInfo = AndroidTaskUtils.getTaskInfoFromTask(appTask); + if (taskInfo == null) continue; + if (tasksToDelete.containsKey(taskInfo.taskId)) { + appTask.finishAndRemoveTask(); + int instanceId = assertNonNull(tasksToDelete.get(taskInfo.taskId)); + ChromeSharedPreferences.getInstance().removeKey(taskMapKey(instanceId)); + } + } + } + private void logNewInstanceId(int i) { StringBuilder taskData = new StringBuilder(); ActivityManager activityManager = @@ -1375,4 +1448,10 @@ syncService.setLocalObservationMode(shouldObserve); } } + + @Override + public boolean showInstanceRestorationMessage(@Nullable MessageDispatcher messageDispatcher) { + return MultiWindowUtils.maybeShowInstanceRestorationMessage( + messageDispatcher, mActivity, this::showInstanceSwitcherDialog); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtils.java index 9594245..26d7370 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtils.java
@@ -35,6 +35,7 @@ import org.chromium.base.ContextUtils; import org.chromium.base.IntentUtils; import org.chromium.base.ResettersForTesting; +import org.chromium.base.SysUtils; import org.chromium.base.TimeUtils; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordUserAction; @@ -58,11 +59,13 @@ import org.chromium.chrome.browser.ui.desktop_windowing.AppHeaderUtils; import org.chromium.chrome.browser.util.AndroidTaskUtils; import org.chromium.components.browser_ui.desktop_windowing.DesktopWindowStateManager; +import org.chromium.components.browser_ui.util.ConversionUtils; import org.chromium.components.messages.MessageBannerProperties; import org.chromium.components.messages.MessageDispatcher; import org.chromium.components.messages.MessageIdentifier; import org.chromium.components.messages.PrimaryActionClickBehavior; import org.chromium.components.ukm.UkmRecorder; +import org.chromium.ui.base.DeviceFormFactor; import org.chromium.ui.modelutil.PropertyModel; import java.lang.annotation.Retention; @@ -189,13 +192,33 @@ * @return The maximum number of instances that a user is allowed to create. */ public static int getMaxInstances() { - return sMaxInstancesForTesting != null - ? sMaxInstancesForTesting - : (isMultiInstanceApi31Enabled() - ? (ChromeFeatureList.sDisableInstanceLimit.isEnabled() - ? TabWindowManager.MAX_SELECTORS - : TabWindowManager.MAX_SELECTORS_S) - : TabWindowManager.MAX_SELECTORS_LEGACY); + if (sMaxInstancesForTesting != null) { + return sMaxInstancesForTesting; + } + + if (!isMultiInstanceApi31Enabled()) { + return TabWindowManager.MAX_SELECTORS_LEGACY; + } + + if (!ChromeFeatureList.sDisableInstanceLimit.isEnabled()) { + return TabWindowManager.MAX_SELECTORS_S; + } + + Context context = ContextUtils.getApplicationContext(); + if (DeviceFormFactor.isNonMultiDisplayContextOnTablet(context)) { + int memoryThresholdMb = + ChromeFeatureList.sDisableInstanceLimitMemoryThresholdMb.getValue(); + boolean isAboveMemoryThreshold = + SysUtils.amountOfPhysicalMemoryKB() + >= memoryThresholdMb * ConversionUtils.KILOBYTES_PER_MEGABYTE; + if (isAboveMemoryThreshold) { + return ChromeFeatureList.sDisableInstanceLimitMaxCount.getValue(); + } else { + return TabWindowManager.MAX_SELECTORS_S; + } + } + + return TabWindowManager.MAX_SELECTORS; } /** Returns the singleton instance of MultiWindowUtils. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java index 7d9d7212..7c3a5c6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
@@ -157,6 +157,8 @@ // Previous visibility states for metrics. private Boolean mPreviousVoiceSearchButtonVisible; private Boolean mPreviousLensButtonVisible; + private @Nullable ImageView mDseIconView; + private ViewGroup mFakeSearchBox; /** Constructor for inflating from XML. */ public NewTabPageLayout(Context context, AttributeSet attrs) { @@ -270,24 +272,11 @@ .getDimensionPixelSize(R.dimen.ntp_search_box_transition_end_offset) : 0; - if (OmniboxFeatures.sOmniboxMobileParityUpdate.isEnabled()) { - var fakeboxView = findViewById(R.id.search_box); - var dseIconView = (ImageView) fakeboxView.findViewById(R.id.search_box_engine_icon); - dseIconView.setVisibility(VISIBLE); - ImageViewCompat.setImageTintList(dseIconView, null); - fakeboxView.setPaddingRelative( - getResources() - .getDimensionPixelSize( - R.dimen.fake_search_box_start_padding_with_dse_logo), - fakeboxView.getPaddingTop(), - fakeboxView.getPaddingEnd(), - fakeboxView.getPaddingBottom()); - } - updateSearchBoxWidth(); initializeLogoCoordinator(searchProviderHasLogo, searchProviderIsGoogle); initializeMostVisitedTilesCoordinator( mProfile, lifecycleDispatcher, tileGroupDelegate, touchEnabledDelegate); + initializeDseIconView(searchProviderIsGoogle); initializeSearchBoxTextView(); initializeVoiceSearchButton(); initializeLensButton(); @@ -353,6 +342,41 @@ TraceEvent.end(TAG + ".initializeSearchBoxTextView()"); } + private void initializeDseIconView(boolean shouldShowDesIconView) { + if (!OmniboxFeatures.sOmniboxMobileParityUpdate.isEnabled()) return; + + mFakeSearchBox = findViewById(R.id.search_box); + mDseIconView = mFakeSearchBox.findViewById(R.id.search_box_engine_icon); + ImageViewCompat.setImageTintList(mDseIconView, null); + + setDseIconViewVisibility(shouldShowDesIconView); + } + + private void setDseIconViewVisibility(boolean isVisible) { + if (mDseIconView == null) return; + + int visibility = isVisible ? VISIBLE : GONE; + if (mDseIconView.getVisibility() == visibility) return; + + mDseIconView.setVisibility(visibility); + + if (isVisible) { + mFakeSearchBox.setPaddingRelative( + getResources() + .getDimensionPixelSize( + R.dimen.fake_search_box_start_padding_with_dse_logo), + mFakeSearchBox.getPaddingTop(), + mFakeSearchBox.getPaddingEnd(), + mFakeSearchBox.getPaddingBottom()); + } else { + mFakeSearchBox.setPaddingRelative( + getResources().getDimensionPixelSize(R.dimen.fake_search_box_start_padding), + mFakeSearchBox.getPaddingTop(), + mFakeSearchBox.getPaddingEnd(), + mFakeSearchBox.getPaddingBottom()); + } + } + private void initializeVoiceSearchButton() { TraceEvent.begin(TAG + ".initializeVoiceSearchButton()"); mVoiceSearchButtonClickListener = v -> mManager.focusSearchBox(true, null); @@ -684,6 +708,9 @@ // Hide or show the views above the most visited tiles as needed, including search box, and // spacers. The visibility of Logo is handled by LogoCoordinator. mSearchBoxCoordinator.setVisibility(mSearchProviderHasLogo); + if (mDseIconView != null) { + setDseIconViewVisibility(mSearchProviderIsGoogle); + } if (mIsComposeplateEnabled) { updateActionButtonVisibility(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java index aa55e84..1db0bff 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
@@ -1137,13 +1137,11 @@ // Initializes Privacy Sandbox related logic recordPrivacySandboxActivityType(profile); - boolean didTriggerPromo = maybeShowRequiredPromptsAndPromos(profile, intentWithEffect); - - if (!didTriggerPromo) { - didTriggerPromo = - RequestDesktopUtils.maybeShowDefaultEnableGlobalSettingMessage( - profile, mMessageDispatcher, mActivity); - } + boolean didTriggerPromo = + maybeShowRequiredPromptsAndPromos(profile, intentWithEffect) + || mMultiInstanceManager.showInstanceRestorationMessage(mMessageDispatcher) + || RequestDesktopUtils.maybeShowDefaultEnableGlobalSettingMessage( + profile, mMessageDispatcher, mActivity); if (!didTriggerPromo) { mToolbarButtonInProductHelpController.showColdStartIph();
diff --git a/chrome/android/javatests/BUILD.gn b/chrome/android/javatests/BUILD.gn index 4da200d..a30c6683 100644 --- a/chrome/android/javatests/BUILD.gn +++ b/chrome/android/javatests/BUILD.gn
@@ -1706,6 +1706,7 @@ "src/org/chromium/chrome/browser/customtabs/CustomTabLaunchCauseMetricsTest.java", "src/org/chromium/chrome/browser/customtabs/features/minimizedcustomtab/MinimizedCardCoordinatorTest.java", "src/org/chromium/chrome/browser/customtabs/features/minimizedcustomtab/MinimizedCardViewBinderTest.java", + "src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsViewBinderTest.java", ] deps = [ ":common_unit_test_deps_java" ]
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsViewBinderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsViewBinderTest.java new file mode 100644 index 0000000..852d185 --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsViewBinderTest.java
@@ -0,0 +1,332 @@ +// 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.customtabs.features.toolbar; + +import static androidx.test.espresso.matcher.ViewMatchers.assertThat; + +import static org.hamcrest.Matchers.instanceOf; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.verify; + +import android.app.Activity; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageButton; + +import androidx.browser.customtabs.CustomTabsIntent; +import androidx.test.annotation.UiThreadTest; +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import org.chromium.base.ThreadUtils; +import org.chromium.base.test.BaseActivityTestRule; +import org.chromium.base.test.util.Batch; +import org.chromium.base.test.util.Feature; +import org.chromium.base.test.util.Features; +import org.chromium.chrome.R; +import org.chromium.chrome.browser.customtabs.features.partialcustomtab.PartialCustomTabSideSheetStrategy.MaximizeButtonCallback; +import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.CloseButtonData; +import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.MinimizeButtonData; +import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.SideSheetMaximizeButtonData; +import org.chromium.chrome.browser.flags.ChromeFeatureList; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.ui.base.ViewUtils; +import org.chromium.ui.modelutil.ListModelChangeProcessor; +import org.chromium.ui.modelutil.PropertyKey; +import org.chromium.ui.modelutil.PropertyListModel; +import org.chromium.ui.modelutil.PropertyModel; +import org.chromium.ui.modelutil.PropertyModelChangeProcessor; +import org.chromium.ui.test.util.BlankUiTestActivity; + +import java.util.concurrent.ExecutionException; + +/** On-device unit tests for {@link CustomTabToolbarButtonsViewBinder}. */ +@RunWith(ChromeJUnit4ClassRunner.class) +@Batch(Batch.UNIT_TESTS) +@Features.EnableFeatures(ChromeFeatureList.CCT_TOOLBAR_REFACTOR) +public class CustomTabToolbarButtonsViewBinderTest { + @Rule + public BaseActivityTestRule<BlankUiTestActivity> mActivityTestRule = + new BaseActivityTestRule<>(BlankUiTestActivity.class); + + @Mock private View.OnClickListener mOnClickListener; + @Mock private MaximizeButtonCallback mMaximizeButtonCallback; + + private Activity mActivity; + private CustomTabToolbar mToolbar; + private PropertyModel mModel; + private PropertyListModel<PropertyModel, PropertyKey> mCustomActionButtons; + + @Before + public void setUp() throws ExecutionException { + MockitoAnnotations.initMocks(this); + mActivityTestRule.launchActivity(null); + mActivity = mActivityTestRule.getActivity(); + + ThreadUtils.runOnUiThreadBlocking( + () -> { + mToolbar = + (CustomTabToolbar) + LayoutInflater.from(mActivity) + .inflate( + R.layout.new_custom_tab_toolbar, + new FrameLayout(mActivity), + false); + mActivity.setContentView(mToolbar); + + mCustomActionButtons = new PropertyListModel<>(); + mModel = + CustomTabToolbarButtonsProperties.create( + /* customActionButtonsVisible= */ true, + mCustomActionButtons, + new MinimizeButtonData(), + new CloseButtonData(), + /* menuButtonVisible= */ true, + /* optionalButtonVisible= */ false, + /* toolbarWidth= */ ViewUtils.dpToPx(mActivity, 500), + /* omniboxEnabled= */ false, + /* titleVisible= */ false, + /* isIncognito= */ false); + + // The view binder uses this tag to get the model. + mToolbar.setTag(R.id.view_model, mModel); + + CustomTabToolbarButtonsViewBinder viewBinder = + new CustomTabToolbarButtonsViewBinder(); + PropertyModelChangeProcessor.create(mModel, mToolbar, viewBinder); + var listMcp = + new ListModelChangeProcessor<>( + mCustomActionButtons, mToolbar, viewBinder); + mCustomActionButtons.addObserver(listMcp); + }); + } + + @Test + @SmallTest + @UiThreadTest + @Feature({"CustomTabs"}) + public void testInitialState() { + assertNull(mToolbar.getCloseButton()); + assertNull(mToolbar.getMinimizeButton()); + assertNotNull(mToolbar.getMenuButton()); + assertEquals(View.VISIBLE, mToolbar.getMenuButton().getVisibility()); + assertNull(mToolbar.getSideSheetMaximizeButton()); + assertEquals(0, mToolbar.getCustomActionButtonsParent().getChildCount()); + } + + @Test + @SmallTest + @UiThreadTest + @Feature({"CustomTabs"}) + public void testCloseButton() { + Drawable icon = new BitmapDrawable(); + mModel.set( + CustomTabToolbarButtonsProperties.CLOSE_BUTTON, + new CloseButtonData( + true, + icon, + CustomTabsIntent.CLOSE_BUTTON_POSITION_START, + mOnClickListener)); + + ImageButton closeButton = mToolbar.getCloseButton(); + assertNotNull(closeButton); + assertEquals(View.VISIBLE, closeButton.getVisibility()); + assertEquals(icon, closeButton.getDrawable()); + closeButton.performClick(); + verify(mOnClickListener).onClick(closeButton); + + // Close button at start, menu at end. + FrameLayout.LayoutParams closeLp = (FrameLayout.LayoutParams) closeButton.getLayoutParams(); + assertEquals(0, closeLp.getMarginStart()); + assertNotEquals("Gravity should be start.", 0, closeLp.gravity & Gravity.START); + FrameLayout.LayoutParams menuLp = + (FrameLayout.LayoutParams) mToolbar.getMenuButton().getLayoutParams(); + assertEquals(0, menuLp.getMarginEnd()); + assertNotEquals("Gravity should be end.", 0, closeLp.gravity & Gravity.END); + } + + @Test + @SmallTest + @UiThreadTest + @Feature({"CustomTabs"}) + public void testCloseButton_End() { + mModel.set( + CustomTabToolbarButtonsProperties.CLOSE_BUTTON, + new CloseButtonData( + true, + new ColorDrawable(), + CustomTabsIntent.CLOSE_BUTTON_POSITION_END, + mOnClickListener)); + ImageButton closeButton = mToolbar.getCloseButton(); + assertNotNull(closeButton); + + // Close button at end, menu at start. + FrameLayout.LayoutParams closeLp = (FrameLayout.LayoutParams) closeButton.getLayoutParams(); + assertEquals(0, closeLp.getMarginEnd()); + assertNotEquals("Gravity should be end.", 0, closeLp.gravity & Gravity.END); + FrameLayout.LayoutParams menuLp = + (FrameLayout.LayoutParams) mToolbar.getMenuButton().getLayoutParams(); + assertEquals(0, menuLp.getMarginStart()); + assertNotEquals("Gravity should be start.", 0, closeLp.gravity & Gravity.START); + } + + @Test + @SmallTest + @UiThreadTest + @Feature({"CustomTabs"}) + public void testMinimizeButton() { + mModel.set( + CustomTabToolbarButtonsProperties.MINIMIZE_BUTTON, + new MinimizeButtonData(true, mOnClickListener)); + + ImageButton minimizeButton = mToolbar.getMinimizeButton(); + assertNotNull(minimizeButton); + assertEquals(View.VISIBLE, minimizeButton.getVisibility()); + minimizeButton.performClick(); + verify(mOnClickListener).onClick(minimizeButton); + } + + @Test + @SmallTest + @UiThreadTest + @Feature({"CustomTabs"}) + public void testSideSheetMaximizeButton() { + mModel.set( + CustomTabToolbarButtonsProperties.SIDE_SHEET_MAXIMIZE_BUTTON, + new SideSheetMaximizeButtonData(true, false, mMaximizeButtonCallback)); + + ImageButton maximizeButton = mToolbar.getSideSheetMaximizeButton(); + assertNotNull(maximizeButton); + assertEquals(View.VISIBLE, maximizeButton.getVisibility()); + maximizeButton.performClick(); + verify(mMaximizeButtonCallback).onClick(); + } + + @Test + @SmallTest + @UiThreadTest + @Feature({"CustomTabs"}) + public void testCustomActionButtons_addUpdateRemove() { + // Add + Drawable icon1 = new ColorDrawable(0xFF0000); + String description1 = "description1"; + PropertyModel buttonModel = + new PropertyModel.Builder(CustomTabToolbarButtonsProperties.INDIVIDUAL_BUTTON_KEYS) + .with(CustomTabToolbarButtonsProperties.ICON, icon1) + .with(CustomTabToolbarButtonsProperties.DESCRIPTION, description1) + .with(CustomTabToolbarButtonsProperties.CLICK_LISTENER, mOnClickListener) + .build(); + mCustomActionButtons.add(buttonModel); + + FrameLayout parent = mToolbar.getCustomActionButtonsParent(); + assertEquals(1, parent.getChildCount()); + + ImageButton button = (ImageButton) parent.getChildAt(0); + assertThat(button, instanceOf(ImageButton.class)); + assertEquals(description1, button.getContentDescription()); + assertEquals(icon1, button.getDrawable()); + + button.performClick(); + verify(mOnClickListener).onClick(button); + + // Update + Drawable icon2 = new ColorDrawable(0x00FF00); + String description2 = "description2"; + + buttonModel.set(CustomTabToolbarButtonsProperties.ICON, icon2); + buttonModel.set(CustomTabToolbarButtonsProperties.DESCRIPTION, description2); + + ImageButton button2 = (ImageButton) parent.getChildAt(0); + assertEquals(icon2, button2.getDrawable()); + assertEquals(description2, button2.getContentDescription()); + + // Remove + mCustomActionButtons.remove(buttonModel); + assertEquals(0, parent.getChildCount()); + } + + @Test + @SmallTest + @UiThreadTest + @Feature({"CustomTabs"}) + public void testOptionalButton() { + + mToolbar.ensureOptionalButtonInflated(); + mModel.set(CustomTabToolbarButtonsProperties.OPTIONAL_BUTTON_VISIBLE, true); + + View optionalButton = mToolbar.getOptionalButton(); + assertNotNull(optionalButton); + assertEquals(View.VISIBLE, optionalButton.getVisibility()); + } + + @Test + @SmallTest + @UiThreadTest + @Feature({"CustomTabs"}) + public void testButtonHiding_notEnoughSpace() { + mModel.set( + CustomTabToolbarButtonsProperties.CLOSE_BUTTON, + new CloseButtonData( + true, + new ColorDrawable(), + CustomTabsIntent.CLOSE_BUTTON_POSITION_START, + mOnClickListener)); + mModel.set( + CustomTabToolbarButtonsProperties.MINIMIZE_BUTTON, + new MinimizeButtonData(true, mOnClickListener)); + mModel.set( + CustomTabToolbarButtonsProperties.SIDE_SHEET_MAXIMIZE_BUTTON, + new SideSheetMaximizeButtonData(true, false, mMaximizeButtonCallback)); + + // All buttons should be visible. + assertNotNull(mToolbar.getCloseButton()); + assertEquals(View.VISIBLE, mToolbar.getCloseButton().getVisibility()); + assertNotNull(mToolbar.getMenuButton()); + assertEquals(View.VISIBLE, mToolbar.getMenuButton().getVisibility()); + assertNotNull(mToolbar.getMinimizeButton()); + assertEquals(View.VISIBLE, mToolbar.getMinimizeButton().getVisibility()); + assertNotNull(mToolbar.getSideSheetMaximizeButton()); + assertEquals(View.VISIBLE, mToolbar.getSideSheetMaximizeButton().getVisibility()); + + // Now set a small width. + mModel.set( + CustomTabToolbarButtonsProperties.TOOLBAR_WIDTH, ViewUtils.dpToPx(mActivity, 200)); + + // With very little space, only the close and menu buttons should be visible. + assertNotNull(mToolbar.getCloseButton()); + assertEquals(View.VISIBLE, mToolbar.getCloseButton().getVisibility()); + assertNotNull(mToolbar.getMenuButton()); + assertEquals(View.VISIBLE, mToolbar.getMenuButton().getVisibility()); + assertNotNull(mToolbar.getMinimizeButton()); + assertEquals(View.GONE, mToolbar.getMinimizeButton().getVisibility()); + assertNotNull(mToolbar.getSideSheetMaximizeButton()); + assertEquals(View.GONE, mToolbar.getSideSheetMaximizeButton().getVisibility()); + } + + @Test + @SmallTest + @UiThreadTest + @Feature({"CustomTabs"}) + public void testIncognito() { + mModel.set(CustomTabToolbarButtonsProperties.IS_INCOGNITO, true); + + assertNotNull(mToolbar.getIncognitoImageView()); + assertEquals(View.VISIBLE, mToolbar.getIncognitoImageView().getVisibility()); + } +}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/settings/ManageSyncSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/settings/ManageSyncSettingsTest.java index 91624c9..1eec4e82 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/settings/ManageSyncSettingsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/settings/ManageSyncSettingsTest.java
@@ -128,7 +128,7 @@ @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) @DoNotBatch(reason = "TODO(crbug.com/40743432): SyncTestRule doesn't support batching.") public class ManageSyncSettingsTest { - private static final int RENDER_TEST_REVISION = 6; + private static final int RENDER_TEST_REVISION = 7; /** Maps selected types to their UI element IDs. */ private Map<Integer, String> mUiDataTypes;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManagerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManagerTest.java index 0ded436..15c48163 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManagerTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManagerTest.java
@@ -311,11 +311,7 @@ var appHeaderState = Mockito.mock(AppHeaderState.class); doReturn(true).when(appHeaderState).isInDesktopWindow(); when(mDesktopWindowStateManager.getAppHeaderState()).thenReturn(appHeaderState); - @ColorInt - int focusedColor = - isNightMode - ? SemanticColorUtils.getColorSurfaceContainer(mActivity) - : SemanticColorUtils.getColorSurfaceContainerHigh(mActivity); + @ColorInt int focusedColor = SemanticColorUtils.getColorSurfaceContainerHigh(mActivity); @ColorInt int unfocusedColor = isNightMode
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31UnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31UnitTest.java index 05cfec54..232c59b 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31UnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31UnitTest.java
@@ -29,6 +29,7 @@ import android.app.ActivityManager.RecentTaskInfo; import android.content.Context; import android.content.Intent; +import android.content.res.Resources; import android.os.Bundle; import android.text.TextUtils; import android.util.Pair; @@ -95,6 +96,7 @@ import org.chromium.components.browser_ui.desktop_windowing.AppHeaderState; import org.chromium.components.browser_ui.desktop_windowing.DesktopWindowStateManager; import org.chromium.components.browser_ui.widget.MenuOrKeyboardActionController; +import org.chromium.components.messages.MessageDispatcher; import org.chromium.components.tab_group_sync.TabGroupSyncService; import org.chromium.ui.modaldialog.ModalDialogManager; import org.chromium.ui.util.XrUtils; @@ -467,6 +469,10 @@ public void tearDown() { ChromeSharedPreferences.getInstance() .removeKeysWithPrefix(ChromePreferenceKeys.MULTI_INSTANCE_TASK_MAP); + ChromeSharedPreferences.getInstance() + .removeKey(ChromePreferenceKeys.MULTI_INSTANCE_INSTANCE_LIMIT_DOWNGRADE_TRIGGERED); + ChromeSharedPreferences.getInstance() + .removeKey(ChromePreferenceKeys.MULTI_INSTANCE_MAX_INSTANCE_LIMIT); TabWindowManagerSingleton.resetTabModelSelectorFactoryForTesting(); ApplicationStatus.destroyForJUnitTests(); mMultiInstanceManager.mTestBuildInstancesList = false; @@ -648,10 +654,8 @@ public void testGetInstanceInfo_closesInstancesOlderThanSixMonths() { MultiWindowTestUtils.enableMultiInstance(); // Setting up two additional Multi-instance managers; mMultiInstanceManager already exists. - MultiInstanceManagerApi31 multiInstanceManager1 = - createMultiInstanceManager(mActivityTask57); - MultiInstanceManagerApi31 multiInstanceManager2 = - createMultiInstanceManager(mActivityTask58); + createMultiInstanceManager(mActivityTask57); + createMultiInstanceManager(mActivityTask58); // Current activity is mActivityTask56, managed by mMultiInstanceManager. assertEquals(0, allocInstanceIndex(PASSED_ID_INVALID, mActivityTask56)); @@ -1563,6 +1567,78 @@ verify(mTabbedActivityTask63).onNewIntent(intent); } + @Test + public void showInstanceRestorationMessage() { + MultiWindowUtils.setInstanceCountForTesting(3); + MultiWindowUtils.setMaxInstancesForTesting(2); + var messageDispatcher = mock(MessageDispatcher.class); + when(mCurrentActivity.getResources()).thenReturn(mock(Resources.class)); + + mMultiInstanceManager.showInstanceRestorationMessage(messageDispatcher); + verify(messageDispatcher).enqueueWindowScopedMessage(any(), eq(false)); + assertTrue( + "SharedPref for tracking restoration message should be updated.", + ChromeSharedPreferences.getInstance() + .readBoolean( + ChromePreferenceKeys.MULTI_INSTANCE_RESTORATION_MESSAGE_SHOWN, + false)); + } + + @Test + public void triggerInstanceLimitDowngrade() { + // Set initial instance limit and allocate ids for max instances. + MultiWindowUtils.setMaxInstancesForTesting(3); + assertEquals(0, allocInstanceIndex(PASSED_ID_INVALID, mActivityTask56)); + mFakeTimeTestRule.advanceMillis(1); + assertEquals(1, allocInstanceIndex(PASSED_ID_INVALID, mActivityTask57)); + mFakeTimeTestRule.advanceMillis(1); + assertEquals(2, allocInstanceIndex(PASSED_ID_INVALID, mActivityTask58)); + + // Decrease instance limit. + MultiWindowUtils.setMaxInstancesForTesting(2); + // Simulate recreation of mActivityTask58 after instance limit downgrade. New allocation + // should result in finishing least recently used activity . + removeTaskOnRecentsScreen(mActivityTask58); + List<AppTask> appTasks = setupActivityManagerAppTasks(mActivityTask56, mActivityTask57); + allocInstanceIndex(2, mActivityTask58); + + verify(appTasks.get(0)).finishAndRemoveTask(); + assertEquals( + "Task map for LRU activity should be updated.", + -1, + MultiInstanceManagerApi31.getTaskFromMap(0)); + assertTrue( + "SharedPref for tracking downgrade should be updated.", + ChromeSharedPreferences.getInstance() + .readBoolean( + ChromePreferenceKeys + .MULTI_INSTANCE_INSTANCE_LIMIT_DOWNGRADE_TRIGGERED, + false)); + + // Subsequent reallocation of an instance should not trigger downgrade path to finish the + // LRU activity task. + destroyActivity(mActivityTask56); + // AppTasks should now contain tasks for instances with id=1 and id=2. + appTasks = setupActivityManagerAppTasks(mActivityTask57, mActivityTask58); + allocInstanceIndex(0, mActivityTask56); + verify(appTasks.get(0), never()).finishAndRemoveTask(); + verify(appTasks.get(1), never()).finishAndRemoveTask(); + } + + private List<AppTask> setupActivityManagerAppTasks(Activity... activities) { + List<AppTask> appTasks = new ArrayList<>(); + for (Activity activity : activities) { + int taskId = activity.getTaskId(); + var appTask = mock(AppTask.class); + var appTaskInfo = mock(RecentTaskInfo.class); + appTaskInfo.taskId = taskId; + when(appTask.getTaskInfo()).thenReturn(appTaskInfo); + appTasks.add(appTask); + } + when(mActivityManager.getAppTasks()).thenReturn(appTasks); + return appTasks; + } + private void doTestOpenInstanceWithValidTask(boolean isActivityAlive) { // Setup mocks to ensure that MultiWindowUtils#createNewWindowIntent() runs as expected. MultiWindowTestUtils.enableMultiInstance(); @@ -1586,40 +1662,30 @@ assertEquals(1, allocInstanceIndex(PASSED_ID_INVALID, mTabbedActivityTask63)); // Setup AppTask's for both activities. - int taskId62 = mTabbedActivityTask62.getTaskId(); - int taskId63 = mTabbedActivityTask63.getTaskId(); - var appTask62 = mock(AppTask.class); - var appTaskInfo62 = mock(RecentTaskInfo.class); - appTaskInfo62.taskId = taskId62; - when(appTask62.getTaskInfo()).thenReturn(appTaskInfo62); - var appTask63 = mock(AppTask.class); - var appTaskInfo63 = mock(RecentTaskInfo.class); - appTaskInfo63.taskId = taskId63; - when(appTask63.getTaskInfo()).thenReturn(appTaskInfo63); - List<AppTask> appTasks = List.of(appTask62, appTask63); - when(mActivityManager.getAppTasks()).thenReturn(appTasks); + List<AppTask> appTasks = + setupActivityManagerAppTasks(mTabbedActivityTask62, mTabbedActivityTask63); if (!isActivityAlive) { // Force destruction of |mTabbedActivityTask63|. destroyActivity(mTabbedActivityTask63); } - // Try to restore the instance in task |taskId63|, from |mTabbedActivityTask62|. - multiInstanceManager.openInstance(1, taskId63); + // Try to restore the instance in task TASK_ID_63, from |mTabbedActivityTask62|. + multiInstanceManager.openInstance(1, TASK_ID_63); if (isActivityAlive) { // If |mTabbedActivityTask63| is alive, verify that its instance was restored in the // existing task by bringing it to the foreground. - verify(mActivityManager).moveTaskToFront(taskId63, 0); + verify(mActivityManager).moveTaskToFront(TASK_ID_63, 0); verify(mTabbedActivityTask62, never()).startActivity(any()); - verify(appTask63, never()).finishAndRemoveTask(); + verify(appTasks.get(1), never()).finishAndRemoveTask(); } else { // If |mTabbedActivityTask63| is not alive, verify that |mTabbedActivityTask62| starts a // new activity and finishes and removes the old task, and does not attempt to bring the // old task to the foreground. verify(mTabbedActivityTask62).startActivity(any()); - verify(appTask63).finishAndRemoveTask(); - verify(mActivityManager, never()).moveTaskToFront(taskId63, 0); + verify(appTasks.get(1)).finishAndRemoveTask(); + verify(mActivityManager, never()).moveTaskToFront(TASK_ID_63, 0); } }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtilsUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtilsUnitTest.java index d9cab811..24e23462 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtilsUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtilsUnitTest.java
@@ -43,14 +43,20 @@ import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; +import org.chromium.base.FeatureOverrides; +import org.chromium.base.SysUtils; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.DisabledTest; +import org.chromium.base.test.util.Features.DisableFeatures; +import org.chromium.base.test.util.Features.EnableFeatures; import org.chromium.base.test.util.HistogramWatcher; +import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.homepage.HomepageManager; import org.chromium.chrome.browser.multiwindow.MultiWindowUtils.InstanceAllocationType; import org.chromium.chrome.browser.multiwindow.MultiWindowUtilsUnitTest.ShadowMultiInstanceManagerApi31; +import org.chromium.chrome.browser.multiwindow.MultiWindowUtilsUnitTest.ShadowSysUtils; import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; import org.chromium.chrome.browser.preferences.ChromeSharedPreferences; import org.chromium.chrome.browser.tab.Tab; @@ -61,6 +67,7 @@ import org.chromium.chrome.test.AutomotiveContextWrapperTestRule; import org.chromium.components.browser_ui.desktop_windowing.AppHeaderState; import org.chromium.components.browser_ui.desktop_windowing.DesktopWindowStateManager; +import org.chromium.components.browser_ui.util.ConversionUtils; import org.chromium.components.embedder_support.util.UrlConstants; import org.chromium.components.messages.MessageBannerProperties; import org.chromium.components.messages.MessageDispatcher; @@ -69,13 +76,16 @@ import org.chromium.url.GURL; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; /** Unit tests for {@link MultiWindowUtils}. */ @RunWith(BaseRobolectricTestRunner.class) @Config( manifest = Config.NONE, - shadows = {ShadowMultiInstanceManagerApi31.class}) + shadows = {ShadowMultiInstanceManagerApi31.class, ShadowSysUtils.class}) public class MultiWindowUtilsUnitTest { /** Shadows {@link MultiInstanceManagerApi31} class for testing. */ @Implements(MultiInstanceManagerApi31.class) @@ -114,6 +124,21 @@ } } + /** Shadows {@link SysUtils} class for testing. */ + @Implements(SysUtils.class) + public static class ShadowSysUtils { + private static int sMemoryInMB; + + public static void setMemoryInMB(int memoryInMB) { + sMemoryInMB = memoryInMB; + } + + @Implementation + public static int amountOfPhysicalMemoryKB() { + return sMemoryInMB * ConversionUtils.KILOBYTES_PER_MEGABYTE; + } + } + @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); @Rule @@ -204,6 +229,8 @@ when(mAppHeaderState.isInDesktopWindow()).thenReturn(false); when(mTabModelSelector.getCurrentTabModelSupplier()).thenReturn(mTabModelSupplier); when(mTabModelSupplier.get()).thenReturn(mNormalTabModel); + + ShadowSysUtils.setMemoryInMB(7000); } @After @@ -857,6 +884,150 @@ verify(messageDispatcher, times(1)).enqueueWindowScopedMessage(any(), anyBoolean()); } + @Test + @DisableFeatures(ChromeFeatureList.DISABLE_INSTANCE_LIMIT) + public void testMaxInstances_DisableInstanceLimitDisabled() { + // Verify instance limit on Android S- devices. + MultiWindowUtils.setMultiInstanceApi31EnabledForTesting(false); + assertEquals( + "Instance limit for Android S- devices is incorrect.", + 3, + MultiWindowUtils.getMaxInstances()); + + // Verify instance limit when FF is disabled. + MultiWindowUtils.setMultiInstanceApi31EnabledForTesting(true); + assertEquals( + "Instance limit when feature is disabled is incorrect.", + 5, + MultiWindowUtils.getMaxInstances()); + } + + @Test + @Config(qualifiers = "sw600dp") + @EnableFeatures(ChromeFeatureList.DISABLE_INSTANCE_LIMIT) + public void testMaxInstances_DefaultValuesOnTablet() { + MultiWindowUtils.setMultiInstanceApi31EnabledForTesting(true); + + // Verify default instance limit for low-memory device, using default memory threshold. + ShadowSysUtils.setMemoryInMB(4000); + assertEquals( + "Instance limit on low-memory tablet device is incorrect.", + 5, + MultiWindowUtils.getMaxInstances()); + + // Verify default instance limit for high-memory device, using default memory threshold. + ShadowSysUtils.setMemoryInMB(7000); + assertEquals( + "Instance limit on high-memory tablet device is incorrect.", + 20, + MultiWindowUtils.getMaxInstances()); + } + + @Test + @Config(qualifiers = "sw600dp") + @EnableFeatures(ChromeFeatureList.DISABLE_INSTANCE_LIMIT) + public void testMaxInstances_CustomInstanceLimit_HighMemoryTablet() { + MultiWindowUtils.setMultiInstanceApi31EnabledForTesting(true); + Map<String, Integer> featureParams = new HashMap<>(); + featureParams.put("max_instance_limit", 50); + updateFeatureParams(ChromeFeatureList.DISABLE_INSTANCE_LIMIT, featureParams); + + assertEquals( + "Instance limit on high-memory tablet device is incorrect.", + 50, + MultiWindowUtils.getMaxInstances()); + } + + @Test + @Config(qualifiers = "sw600dp") + @EnableFeatures(ChromeFeatureList.DISABLE_INSTANCE_LIMIT) + public void testMaxInstances_CustomInstanceLimit_LowMemoryTablet() { + MultiWindowUtils.setMultiInstanceApi31EnabledForTesting(true); + ShadowSysUtils.setMemoryInMB(4000); + Map<String, Integer> featureParams = new HashMap<>(); + featureParams.put("max_instance_limit", 50); + updateFeatureParams(ChromeFeatureList.DISABLE_INSTANCE_LIMIT, featureParams); + + assertEquals( + "Instance limit on high-memory tablet device is incorrect.", + 5, + MultiWindowUtils.getMaxInstances()); + } + + @Test + @Config(qualifiers = "sw600dp") + @EnableFeatures(ChromeFeatureList.DISABLE_INSTANCE_LIMIT) + public void testMaxInstances_CustomMemoryThreshold_HighMemoryTablet() { + MultiWindowUtils.setMultiInstanceApi31EnabledForTesting(true); + ShadowSysUtils.setMemoryInMB(8500); + Map<String, Integer> featureParams = new HashMap<>(); + featureParams.put("max_instance_limit_memory_threshold_mb", 8000); + updateFeatureParams(ChromeFeatureList.DISABLE_INSTANCE_LIMIT, featureParams); + + assertEquals( + "Instance limit on high-memory tablet device is incorrect.", + 20, + MultiWindowUtils.getMaxInstances()); + } + + @Test + @Config(qualifiers = "sw600dp") + @EnableFeatures(ChromeFeatureList.DISABLE_INSTANCE_LIMIT) + public void testMaxInstances_CustomMemoryThreshold_LowMemoryTablet() { + MultiWindowUtils.setMultiInstanceApi31EnabledForTesting(true); + ShadowSysUtils.setMemoryInMB(7500); + Map<String, Integer> featureParams = new HashMap<>(); + featureParams.put("max_instance_limit_memory_threshold_mb", 8000); + updateFeatureParams(ChromeFeatureList.DISABLE_INSTANCE_LIMIT, featureParams); + + assertEquals( + "Instance limit on low-memory tablet device is incorrect.", + 5, + MultiWindowUtils.getMaxInstances()); + } + + @Test + @Config(qualifiers = "sw600dp") + @EnableFeatures(ChromeFeatureList.DISABLE_INSTANCE_LIMIT) + public void testMaxInstances_CustomInstanceLimit_CustomMemoryThreshold_HighMemoryTablet() { + MultiWindowUtils.setMultiInstanceApi31EnabledForTesting(true); + ShadowSysUtils.setMemoryInMB(8500); + Map<String, Integer> featureParams = new HashMap<>(); + featureParams.put("max_instance_limit", 50); + featureParams.put("max_instance_limit_memory_threshold_mb", 8000); + updateFeatureParams(ChromeFeatureList.DISABLE_INSTANCE_LIMIT, featureParams); + + assertEquals( + "Instance limit on high-memory tablet device is incorrect.", + 50, + MultiWindowUtils.getMaxInstances()); + } + + @Test + @Config(qualifiers = "sw600dp") + @EnableFeatures(ChromeFeatureList.DISABLE_INSTANCE_LIMIT) + public void testMaxInstances_CustomInstanceLimit_CustomMemoryThreshold_LowMemoryTablet() { + MultiWindowUtils.setMultiInstanceApi31EnabledForTesting(true); + ShadowSysUtils.setMemoryInMB(7500); + Map<String, Integer> featureParams = new HashMap<>(); + featureParams.put("max_instance_limit", 50); + featureParams.put("max_instance_limit_memory_threshold_mb", 8000); + updateFeatureParams(ChromeFeatureList.DISABLE_INSTANCE_LIMIT, featureParams); + + assertEquals( + "Instance limit on low-memory tablet device is incorrect.", + 5, + MultiWindowUtils.getMaxInstances()); + } + + private void updateFeatureParams(String feature, Map<String, Integer> featureParams) { + FeatureOverrides.Builder overrides = FeatureOverrides.newBuilder().enable(feature); + for (Entry<String, Integer> entry : featureParams.entrySet()) { + overrides = overrides.param(entry.getKey(), entry.getValue()); + } + overrides.apply(); + } + private void testRecordTabCountForRelaunchWhenActivityPausedImpl(int windowId) { String tabCountForRelaunchKey = MultiWindowUtils.getTabCountForRelaunchKey(windowId);
diff --git a/chrome/android/modules/readaloud/public/java/src/org/chromium/chrome/modules/readaloud/PlaybackListener.java b/chrome/android/modules/readaloud/public/java/src/org/chromium/chrome/modules/readaloud/PlaybackListener.java index df830d4..5661f9a 100644 --- a/chrome/android/modules/readaloud/public/java/src/org/chromium/chrome/modules/readaloud/PlaybackListener.java +++ b/chrome/android/modules/readaloud/public/java/src/org/chromium/chrome/modules/readaloud/PlaybackListener.java
@@ -21,7 +21,8 @@ State.BUFFERING, State.PAUSED, State.PLAYING, - State.STOPPED + State.STOPPED, + State.PLAYBACK_CREATION, }) @Retention(RetentionPolicy.SOURCE) public @interface State { @@ -42,6 +43,9 @@ /** Stopped; represents end of playback. */ int STOPPED = 6; + + /** Playback is being created. */ + int PLAYBACK_CREATION = 7; } /** Information about playback. */
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index e842239..d7c51be 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -149,6 +149,35 @@ ] } +source_set("flags") { + sources = [ + "about_flags.h", + "flag_descriptions.h", + ] + public_deps = [ + "//base", + "//base:debugging_buildflags", + "//build:branding_buildflags", + "//build:buildflag_header_h", + "//chrome/common:buildflags", + "//components/compose:buildflags", + "//components/enterprise/buildflags", + "//components/nacl/common:buildflags", + "//components/paint_preview/buildflags", + "//components/signin/public/base:signin_buildflags", + "//components/webui/flags", + "//content/public/common", + "//device/vr/buildflags", + "//extensions/buildflags", + "//media:media_buildflags", + "//net:buildflags", + "//pdf:buildflags", + "//printing/buildflags", + "//skia:buildflags", + "//third_party/blink/public/common:buildflags", + ] +} + source_set("shell_integration") { sources = [ "shell_integration.h" ] deps = [ @@ -163,7 +192,6 @@ static_library("browser") { sources = [ "about_flags.cc", - "about_flags.h", "accessibility/accessibility_labels_service.cc", "accessibility/accessibility_labels_service.h", "accessibility/accessibility_labels_service_factory.cc", @@ -548,7 +576,6 @@ "first_party_sets/first_party_sets_policy_service_factory.cc", "first_party_sets/first_party_sets_policy_service_factory.h", "flag_descriptions.cc", - "flag_descriptions.h", "font_family_cache.cc", "font_family_cache.h", "gcm/gcm_product_util.cc", @@ -8496,6 +8523,13 @@ # generated files here. ":browser_generated_files", + # To avoid that the huge amount of source files that include either + # "about_flags.h" or "flag_description.h" to depend directly on //c/b:flags + # for now, it is added temporarily as a public dependency of //c/b:b. + # + # TODO(crbug.com/369436587): Make all targets that include these headers to depend directly //c/b:flags. + ":flags", + # //chrome/browser/ui and //chrome/browser are semantically the same target, # and thus their public dependencies are shared. "//base",
diff --git a/chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_utils_unittest.cc b/chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_utils_unittest.cc index 9e39990..5fb19e7 100644 --- a/chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_utils_unittest.cc +++ b/chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_utils_unittest.cc
@@ -309,31 +309,6 @@ ASSERT_FALSE(IsEligibleForSeaPenTextInput(regular_profile)); } -TEST_F(PersonalizationAppUtilsTest, - IsEligibleForSeaPenTextInput_WithoutSeaPenTextInput_AdultUser) { - const std::string email = "unknown@example.com"; - auto* regular_profile = profile_manager().CreateTestingProfile(email); - auto* identity_manager = - IdentityManagerFactory::GetForProfile(regular_profile); - // Set up gaia id. - ash::FakeChromeUserManager* user_manager = - static_cast<ash::FakeChromeUserManager*>( - user_manager::UserManager::Get()); - AccountInfo primary_account = signin::MakePrimaryAccountAvailable( - identity_manager, email, signin::ConsentLevel::kSignin); - const AccountId account_id = - AccountId::FromUserEmailGaiaId(email, primary_account.gaia); - user_manager->AddUser(account_id); - user_manager->LoginUser(account_id); - - // Set up capability. - AccountCapabilitiesTestMutator mutator(&primary_account.capabilities); - mutator.set_can_use_manta_service(true); - signin::UpdateAccountInfoForAccount(identity_manager, primary_account); - - ASSERT_FALSE(IsEligibleForSeaPenTextInput(regular_profile)); -} - TEST_F(PersonalizationAppUtilsTest, IsEligibleForSeaPenTextInput_AdultUser) { base::test::ScopedFeatureList features(features::kSeaPenTextInput); const std::string email = "unknown@example.com";
diff --git a/chrome/browser/ash/wallpaper_handlers/sea_pen_fetcher_unittest.cc b/chrome/browser/ash/wallpaper_handlers/sea_pen_fetcher_unittest.cc index afc6fb6..40b2923 100644 --- a/chrome/browser/ash/wallpaper_handlers/sea_pen_fetcher_unittest.cc +++ b/chrome/browser/ash/wallpaper_handlers/sea_pen_fetcher_unittest.cc
@@ -54,7 +54,7 @@ constexpr std::string_view kThumbnailsTimeoutMetric = "Ash.SeaPen.Api.Thumbnails.Timeout"; constexpr std::string_view kThumbnailsCountMetric = - "Ash.SeaPen.Api.Thumbnails.Count"; + "Ash.SeaPen.Api.Thumbnails.Count2"; constexpr std::string_view kWallpaperLatencyMetric = "Ash.SeaPen.Api.Wallpaper.Latency"; @@ -251,69 +251,7 @@ std::unique_ptr<SeaPenFetcher> sea_pen_fetcher_; }; -TEST_F(SeaPenFetcherTest, ThumbnailsCallsSnapperProvider) { - auto query = MakeTemplateQuery(); - - EXPECT_CALL( - snapper_provider(), - Call(base::test::EqualsProto(CreateMantaRequest( - query, /*generation_seed=*/std::nullopt, - /*num_outputs=*/SeaPenFetcher::kNumTemplateThumbnailsRequested, - {880, 440}, manta::proto::FeatureName::CHROMEOS_WALLPAPER)), - testing::_, testing::_)) - .WillOnce([](const manta::proto::Request& request, - net::NetworkTrafficAnnotationTag traffic_annotation, - manta::MantaProtoResponseCallback done_callback) { - base::SequencedTaskRunner::GetCurrentDefault()->PostTask( - FROM_HERE, - base::BindOnce( - [](manta::MantaProtoResponseCallback delayed_callback) { - std::move(delayed_callback) - .Run(CreateMantaResponse( - SeaPenFetcher::kNumTemplateThumbnailsRequested), - {.status_code = manta::MantaStatusCode::kOk, - .message = std::string()}); - }, - std::move(done_callback))); - }); - - base::test::TestFuture<std::optional<std::vector<ash::SeaPenImage>>, - manta::MantaStatusCode> - fetch_thumbnails_future; - - sea_pen_fetcher()->FetchThumbnails( - manta::proto::FeatureName::CHROMEOS_WALLPAPER, query, - fetch_thumbnails_future.GetCallback()); - - EXPECT_EQ(manta::MantaStatusCode::kOk, - fetch_thumbnails_future.Get<manta::MantaStatusCode>()); - - std::vector<testing::Matcher<ash::SeaPenImage>> matchers; - for (size_t i = 0; i < SeaPenFetcher::kNumTemplateThumbnailsRequested; i++) { - matchers.push_back( - MatchesSeaPenImage(CreateTestBitmap(), kFakeGenerationSeed + i)); - } - EXPECT_THAT(fetch_thumbnails_future - .Get<std::optional<std::vector<ash::SeaPenImage>>>() - .value(), - testing::UnorderedElementsAreArray(matchers)); - - histogram_tester().ExpectTotalCount(kThumbnailsLatencyMetric, 1); - histogram_tester().ExpectUniqueSample(kThumbnailsTimeoutMetric, false, 1); - histogram_tester().ExpectUniqueSample( - kThumbnailsCountMetric, SeaPenFetcher::kNumTemplateThumbnailsRequested, - 1); -} - -TEST_F(SeaPenFetcherTest, TemplateRequestsFourImages_withTextInputOn) { - scoped_feature_list_.Reset(); - scoped_feature_list_.InitWithFeatures( - { - ash::features::kFeatureManagementSeaPen, - manta::features::kMantaService, - ash::features::kSeaPenTextInput, - }, - {}); +TEST_F(SeaPenFetcherTest, TemplateRequestsFourImages) { auto query = MakeTemplateQuery(); EXPECT_CALL(
diff --git a/chrome/browser/bookmarks/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkBatchUploadCardRenderTest.java b/chrome/browser/bookmarks/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkBatchUploadCardRenderTest.java index 3d5dbd6..f73d69b 100644 --- a/chrome/browser/bookmarks/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkBatchUploadCardRenderTest.java +++ b/chrome/browser/bookmarks/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkBatchUploadCardRenderTest.java
@@ -44,7 +44,7 @@ @DoNotBatch(reason = "SyncTestRule doesn't support batching.") @EnableFeatures({ChromeFeatureList.UNO_PHASE_2_FOLLOW_UP}) public class BookmarkBatchUploadCardRenderTest { - private static final int RENDER_TEST_REVISION = 1; + private static final int RENDER_TEST_REVISION = 2; @Rule public final SyncTestRule mSyncTestRule = new SyncTestRule(); @Rule public final BookmarkTestRule mBookmarkTestRule = new BookmarkTestRule();
diff --git a/chrome/browser/contextual_cueing/BUILD.gn b/chrome/browser/contextual_cueing/BUILD.gn index 71585b1..dcef2b1 100644 --- a/chrome/browser/contextual_cueing/BUILD.gn +++ b/chrome/browser/contextual_cueing/BUILD.gn
@@ -33,6 +33,7 @@ "zero_state_suggestions_page_data.h", ] deps = [ + "//chrome/browser:browser_process", "//chrome/browser/content_extraction", "//chrome/browser/contextual_cueing", "//chrome/browser/optimization_guide",
diff --git a/chrome/browser/contextual_cueing/zero_state_suggestions_page_data.cc b/chrome/browser/contextual_cueing/zero_state_suggestions_page_data.cc index 0911e6f..60a0e0d 100644 --- a/chrome/browser/contextual_cueing/zero_state_suggestions_page_data.cc +++ b/chrome/browser/contextual_cueing/zero_state_suggestions_page_data.cc
@@ -9,6 +9,7 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/task/single_thread_task_runner.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/content_extraction/inner_text.h" #include "chrome/browser/contextual_cueing/contextual_cueing_features.h" #include "chrome/browser/contextual_cueing/contextual_cueing_helper.h" @@ -251,6 +252,9 @@ suggestions_request_->set_is_fre(is_fre); *suggestions_request_->mutable_supported_tools() = {supported_tools.begin(), supported_tools.end()}; + if (g_browser_process) { + suggestions_request_->set_locale(g_browser_process->GetApplicationLocale()); + } suggestions_callbacks_.AddUnsafe(std::move(callback)); RequestSuggestionsIfComplete(); }
diff --git a/chrome/browser/enterprise/data_protection/data_protection_navigation_observer.cc b/chrome/browser/enterprise/data_protection/data_protection_navigation_observer.cc index 77ccc2d..56c12d9 100644 --- a/chrome/browser/enterprise/data_protection/data_protection_navigation_observer.cc +++ b/chrome/browser/enterprise/data_protection/data_protection_navigation_observer.cc
@@ -134,7 +134,6 @@ bool is_cached, std::unique_ptr<safe_browsing::RTLookupResponse> rt_lookup_response) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - if (!is_success) { rt_lookup_response.reset(); } @@ -315,6 +314,7 @@ DataProtectionNavigationDelegate* delegate, Callback callback) : content::WebContentsObserver(web_contents), + navigation_id_(navigation_handle.GetNavigationId()), lookup_service_(lookup_service), delegate_(delegate), pending_navigation_callback_(std::move(callback)) { @@ -339,6 +339,8 @@ base::BindOnce(&DataProtectionNavigationObserver::OnLookupComplete, weak_factory_.GetWeakPtr()), navigation_handle.GetWebContents()); + } else { + is_verdict_received_ = true; } } @@ -348,8 +350,16 @@ std::unique_ptr<safe_browsing::RTLookupResponse> rt_lookup_response) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(!is_from_cache_); + is_verdict_received_ = true; + if (is_navigation_finished_) { + OnDoLookupComplete(web_contents()->GetWeakPtr(), + std::move(pending_navigation_callback_), identifier_, + std::move(rt_lookup_response)); + } else { + rt_lookup_response_ = std::move(rt_lookup_response); + } - rt_lookup_response_ = std::move(rt_lookup_response); + MaybeCleanup(); } bool DataProtectionNavigationObserver::ShouldPerformRealTimeUrlCheck( @@ -377,16 +387,19 @@ } } -void DataProtectionNavigationObserver::Cleanup(int64_t navigation_id) { - DCHECK(delegate_); - delegate_->Cleanup(navigation_id); +void DataProtectionNavigationObserver::MaybeCleanup() { + if (is_navigation_finished_ && is_verdict_received_) { + DCHECK(delegate_); + delegate_->Cleanup(navigation_id_); + } } void DataProtectionNavigationObserver::DidFinishNavigation( content::NavigationHandle* navigation_handle) { - base::ScopedClosureRunner done(base::BindOnce( - &DataProtectionNavigationObserver::Cleanup, weak_factory_.GetWeakPtr(), - navigation_handle->GetNavigationId())); + is_navigation_finished_ = true; + base::ScopedClosureRunner done( + base::BindOnce(&DataProtectionNavigationObserver::MaybeCleanup, + weak_factory_.GetWeakPtr())); // Only consider primary main frame commits, which will come eventually. // Even though some of these checks where already performed in @@ -396,8 +409,8 @@ // `pending_navigation_callback_` being null implies `DidFinishNavigation` // has already been called, so further lookups/metrics code need to run. if (!navigation_handle->IsInPrimaryMainFrame() || - !navigation_handle->HasCommitted() || - !pending_navigation_callback_) { + !navigation_handle->HasCommitted() || !pending_navigation_callback_ || + !is_verdict_received_) { return; }
diff --git a/chrome/browser/enterprise/data_protection/data_protection_navigation_observer.h b/chrome/browser/enterprise/data_protection/data_protection_navigation_observer.h index 90e3fc60..410cd064 100644 --- a/chrome/browser/enterprise/data_protection/data_protection_navigation_observer.h +++ b/chrome/browser/enterprise/data_protection/data_protection_navigation_observer.h
@@ -78,8 +78,8 @@ // monitor the whole navigation. // // The created DataProtectionNavigationObserver will delete itself when the - // navigation completes, by calling Cleanup() when DidFinishNavigation() goes - // out of scope. + // navigation completes, by calling MaybeCleanup() when DidFinishNavigation() + // goes out of scope. static std::unique_ptr<DataProtectionNavigationObserver> CreateForNavigationIfNeeded(DataProtectionNavigationDelegate* delegate, Profile* profile, @@ -114,7 +114,7 @@ void OnLookupComplete( std::unique_ptr<safe_browsing::RTLookupResponse> rt_lookup_response); - void Cleanup(int64_t navigation_id); + void MaybeCleanup(); // Returns true when the "EnterpriseRealTimeUrlCheckMode" policy is enabled // for `browser_context`, and when a `lookup_service_` is available to make @@ -130,6 +130,12 @@ bool is_from_cache_ = false; + bool is_navigation_finished_ = false; + + bool is_verdict_received_ = false; + + int64_t navigation_id_; + // Screenshots are allowed unless explicitly blocked. bool allow_screenshot_ = true;
diff --git a/chrome/browser/enterprise/data_protection/data_protection_navigation_observer_unittest.cc b/chrome/browser/enterprise/data_protection/data_protection_navigation_observer_unittest.cc index 735e863..3f9528e 100644 --- a/chrome/browser/enterprise/data_protection/data_protection_navigation_observer_unittest.cc +++ b/chrome/browser/enterprise/data_protection/data_protection_navigation_observer_unittest.cc
@@ -8,6 +8,7 @@ #include <optional> #include "base/memory/raw_ptr.h" +#include "base/test/bind.h" #include "base/test/test_future.h" #include "base/values.h" #include "chrome/browser/enterprise/connectors/connectors_service.h" @@ -279,58 +280,6 @@ DataProtectionNavigationObserver::NavigationObservers navigation_observers_; }; -TEST_F(DataProtectionNavigationObserverTest, TestWatermarkTextUpdated) { - chrome::cros::reporting::proto::UrlFilteringInterstitialEvent expected_event; - expected_event.set_url("https://test/"); - expected_event.set_event_result( - chrome::cros::reporting::proto::EVENT_RESULT_ALLOWED); - expected_event.set_profile_user_name("test-user@chromium.org"); - expected_event.set_profile_identifier(profile()->GetPath().AsUTF8Unsafe()); - *expected_event.add_triggered_rule_info() = - MakeTriggeredRuleInfo(/*has_watermark=*/true); - - enterprise_connectors::test::EventReportValidator validator(client_.get()); - validator.ExpectURLFilteringInterstitialEvent(expected_event); - - base::test::TestFuture<const UrlSettings&> future; - FakeDataProtectionNavigationController controller( - web_contents(), &lookup_service_, future.GetCallback()); - - base::test::TestFuture<void> future_lookup_complete; - lookup_service_.set_on_start_lookup_complete( - future_lookup_complete.GetCallback()); - - auto simulator = content::NavigationSimulator::CreateRendererInitiated( - GURL("https://test"), web_contents()->GetPrimaryMainFrame()); - - // DataProtectionNavigationObserver does not implement DidStartNavigation(), - // this is called by DataProtectionNavigationController. So we simply call - // Start() and manually construct the class using the navigation handle that - // is provided once Start() is called. - simulator->Start(); - EXPECT_TRUE(future_lookup_complete.Wait()); - - // Call DidFinishNavigation() navigation, which should invoke our callback. - simulator->Commit(); - - std::string watermark_text = future.Get().watermark_text; - Profile* profile = Profile::FromBrowserContext(browser_context()); - auto* connectors_service = - enterprise_connectors::ConnectorsServiceFactory::GetForBrowserContext( - profile); - EXPECT_EQ(watermark_text, - "custom_message\n" + - connectors_service->GetRealTimeUrlCheckIdentifier() + - "\n2024-02-29T04:36:04.000Z"); - - // Value should be cached. - auto* user_data = DataProtectionPageUserData::GetForPage( - GetPageFromWebContents(web_contents())); - ASSERT_TRUE(user_data); - EXPECT_NE(user_data->settings().watermark_text.find("custom_message"), - std::string::npos); -} - TEST_F(DataProtectionNavigationObserverTest, MatchedAuditRuleHasEvent) { chrome::cros::reporting::proto::UrlFilteringInterstitialEvent expected_event; expected_event.set_url("https://example.com/"); @@ -981,4 +930,70 @@ SinglePageAppWatermarkTest, testing::Bool()); +class OrderedDataProtectionNavigationObserverTest + : public DataProtectionNavigationObserverTest, + public testing::WithParamInterface<bool> { + public: + bool IsNavigationFinishedAfterVerdictReceived() const { return GetParam(); } +}; + +TEST_P(OrderedDataProtectionNavigationObserverTest, TestWatermarkTextUpdated) { + chrome::cros::reporting::proto::UrlFilteringInterstitialEvent expected_event; + expected_event.set_url("https://test/"); + expected_event.set_event_result( + chrome::cros::reporting::proto::EVENT_RESULT_ALLOWED); + expected_event.set_profile_user_name("test-user@chromium.org"); + expected_event.set_profile_identifier(profile()->GetPath().AsUTF8Unsafe()); + *expected_event.add_triggered_rule_info() = + MakeTriggeredRuleInfo(/*has_watermark=*/true); + + enterprise_connectors::test::EventReportValidator validator(client_.get()); + validator.ExpectURLFilteringInterstitialEvent(expected_event); + + base::test::TestFuture<const UrlSettings&> future; + FakeDataProtectionNavigationController controller( + web_contents(), &lookup_service_, future.GetCallback()); + + base::test::TestFuture<void> future_lookup_complete; + lookup_service_.set_on_start_lookup_complete( + future_lookup_complete.GetCallback()); + + auto simulator = content::NavigationSimulator::CreateRendererInitiated( + GURL("https://test"), web_contents()->GetPrimaryMainFrame()); + + // DataProtectionNavigationObserver does not implement DidStartNavigation(), + // this is called by DataProtectionNavigationController. So we simply call + // Start() and manually construct the class using the navigation handle that + // is provided once Start() is called. + simulator->Start(); + if (IsNavigationFinishedAfterVerdictReceived()) { + EXPECT_TRUE(future_lookup_complete.Wait()); + simulator->Commit(); + } else { + simulator->Commit(); + EXPECT_TRUE(future_lookup_complete.Wait()); + } + + std::string watermark_text = future.Get().watermark_text; + Profile* profile = Profile::FromBrowserContext(browser_context()); + auto* connectors_service = + enterprise_connectors::ConnectorsServiceFactory::GetForBrowserContext( + profile); + EXPECT_EQ(watermark_text, + "custom_message\n" + + connectors_service->GetRealTimeUrlCheckIdentifier() + + "\n2024-02-29T04:36:04.000Z"); + + // Value should be cached. + auto* user_data = DataProtectionPageUserData::GetForPage( + GetPageFromWebContents(web_contents())); + ASSERT_TRUE(user_data); + EXPECT_NE(user_data->settings().watermark_text.find("custom_message"), + std::string::npos); +} + +INSTANTIATE_TEST_SUITE_P(OrderedDataProtectionNavigationObserverTest, + OrderedDataProtectionNavigationObserverTest, + testing::Bool()); + } // namespace enterprise_data_protection
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc index f075287..0c84accf 100644 --- a/chrome/browser/extensions/api/settings_private/prefs_util.cc +++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -1310,6 +1310,8 @@ settings_api::PrefType::kBoolean; (*s_allowlist)[glic::prefs::kGlicTabContextEnabled] = settings_api::PrefType::kBoolean; + (*s_allowlist)[glic::prefs::kGlicUserStatus] = + settings_api::PrefType::kDictionary; (*s_allowlist)[prefs::kGeminiSettings] = settings_api::PrefType::kNumber; }
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java index 1b064077..f84c7d25 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -1456,6 +1456,12 @@ "max_legacy_tab_state_files_deleted_per_session", 100); + public static final IntCachedFeatureParam sDisableInstanceLimitMemoryThresholdMb = + newIntCachedFeatureParam( + DISABLE_INSTANCE_LIMIT, "max_instance_limit_memory_threshold_mb", 6500); + public static final IntCachedFeatureParam sDisableInstanceLimitMaxCount = + newIntCachedFeatureParam(DISABLE_INSTANCE_LIMIT, "max_instance_limit", 20); + /** Cached param whether we disable e2e on the recent tabs page. */ public static final BooleanCachedFeatureParam sDrawKeyNativeEdgeToEdgeDisableRecentTabsE2e = newBooleanCachedFeatureParam( @@ -1669,6 +1675,8 @@ sCollectAndroidFrameTimelineMetricsJankTrackerDelayedStartMs, sDeleteLegacyTabStateFilesBatchSize, sDeleteMigratedLegacyTabStateFilesAfterRestore, + sDisableInstanceLimitMaxCount, + sDisableInstanceLimitMemoryThresholdMb, sDrawKeyNativeEdgeToEdgeDisableCctMediaViewerE2e, sDrawKeyNativeEdgeToEdgeDisableHubE2e, sDrawKeyNativeEdgeToEdgeDisableIncognitoNtpE2e,
diff --git a/chrome/browser/glic/fre/glic_fre_controller.cc b/chrome/browser/glic/fre/glic_fre_controller.cc index d66b3a1..761961aa 100644 --- a/chrome/browser/glic/fre/glic_fre_controller.cc +++ b/chrome/browser/glic/fre/glic_fre_controller.cc
@@ -81,9 +81,10 @@ } bool GlicFreController::ShouldShowFreDialog() { - // If the given profile has not previously completed the FRE, then it should - // be shown. - return !GlicEnabling::HasConsentedForProfile(profile_); + // If the given profile has not previously completed the FRE and is eligible, + // then it should be shown. + return GlicEnabling::IsEnabledForProfile(profile_) && + !GlicEnabling::HasConsentedForProfile(profile_); } bool GlicFreController::CanShowFreDialog(Browser* browser) {
diff --git a/chrome/browser/glic/glic_enabling.cc b/chrome/browser/glic/glic_enabling.cc index a425dba6..8e39a17e 100644 --- a/chrome/browser/glic/glic_enabling.cc +++ b/chrome/browser/glic/glic_enabling.cc
@@ -131,7 +131,7 @@ mojom::ProfileReadyState GlicEnabling::GetProfileReadyState(Profile* profile) { if (!IsEnabledAndConsentForProfile(profile)) { - return mojom::ProfileReadyState::kUnknownError; + return mojom::ProfileReadyState::kIneligible; } auto* command_line = base::CommandLine::ForCurrentProcess();
diff --git a/chrome/browser/glic/glic_policy_browsertest.cc b/chrome/browser/glic/glic_policy_browsertest.cc index a5f9ad88..2bf840ac 100644 --- a/chrome/browser/glic/glic_policy_browsertest.cc +++ b/chrome/browser/glic/glic_policy_browsertest.cc
@@ -192,6 +192,30 @@ provider.UpdateChromePolicy(policies); } + // Simulates a click on an element with the given |id|. + void ClickElementWithId(content::WebContents* web_contents, + const std::string& id) { + // Get the center coordinates of the DOM element. + const int x = + EvalJs(web_contents, + content::JsReplace("const bounds = " + "document.getElementById($1)." + "getBoundingClientRect();" + "Math.floor(bounds.left + bounds.width / 2)", + id)) + .ExtractInt(); + const int y = + EvalJs(web_contents, + content::JsReplace("const bounds = " + "document.getElementById($1)." + "getBoundingClientRect();" + "Math.floor(bounds.top + bounds.height / 2)", + id)) + .ExtractInt(); + SimulateMouseClickAt(web_contents, 0, blink::WebMouseEvent::Button::kLeft, + gfx::Point(x, y)); + } + testing::NiceMock<policy::MockConfigurationPolicyProvider>& policy_for_profile_1() { // This comes from the PolicyTest base class. @@ -521,6 +545,22 @@ })) << "Timed out waiting for unavailable state. Current state: " << service->host().GetPrimaryWebUiState(); ASSERT_TRUE(service->window_controller().IsShowing()); + +// Flakiness on linux. +#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) + // TODO(crbug.com/426583248) Wait for animation to finish instead of using the + // arbitrary 1000ms wait. + base::RunLoop run_loop; + base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask( + FROM_HERE, run_loop.QuitClosure(), base::Milliseconds(1000)); + run_loop.Run(); + ClickElementWithId( + service->window_controller().GetGlicView()->GetWebContents(), + "profilePickerButton"); + ASSERT_TRUE(base::test::RunUntil([&]() { + return !service->window_controller().IsShowing(); + })) << "Timed out waiting for glic to close"; +#endif } // Ensure the chrome://settings page for Glic is available when the feature is
diff --git a/chrome/browser/glic/host/glic.mojom b/chrome/browser/glic/host/glic.mojom index a5abf82a..b73adb2 100644 --- a/chrome/browser/glic/host/glic.mojom +++ b/chrome/browser/glic/host/glic.mojom
@@ -22,6 +22,8 @@ kSignInRequired, // The profile is ready for Glic. kReady, + // The profile is not eligible for Glic. + kIneligible, }; // Functions provided by the WebUI page. @@ -103,6 +105,9 @@ // Closes the Glic panel. ClosePanel(); + // Opens the profile picker, and closes the Glic panel. + OpenProfilePickerAndClosePanel(); + // Opens the sign-in page, and closes the Glic panel. SignInAndClosePanel();
diff --git a/chrome/browser/glic/host/glic_page_handler.cc b/chrome/browser/glic/host/glic_page_handler.cc index 392533d..b5fab98e 100644 --- a/chrome/browser/glic/host/glic_page_handler.cc +++ b/chrome/browser/glic/host/glic_page_handler.cc
@@ -1031,6 +1031,11 @@ GetGlicService()->ClosePanel(); } +void GlicPageHandler::OpenProfilePickerAndClosePanel() { + glic::GlicProfileManager::GetInstance()->ShowProfilePicker(); + GetGlicService()->window_controller().Close(); +} + void GlicPageHandler::SignInAndClosePanel() { GetGlicService()->GetAuthController().ShowReauthForAccount(base::BindOnce( &GlicWindowController::ShowAfterSignIn,
diff --git a/chrome/browser/glic/host/glic_page_handler.h b/chrome/browser/glic/host/glic_page_handler.h index da841fc..1ec7be28f 100644 --- a/chrome/browser/glic/host/glic_page_handler.h +++ b/chrome/browser/glic/host/glic_page_handler.h
@@ -58,6 +58,8 @@ void ClosePanel() override; + void OpenProfilePickerAndClosePanel() override; + void SignInAndClosePanel() override; void ResizeWidget(const gfx::Size& size,
diff --git a/chrome/browser/glic/host/glic_ui.cc b/chrome/browser/glic/host/glic_ui.cc index fe3c813..5e84559 100644 --- a/chrome/browser/glic/host/glic_ui.cc +++ b/chrome/browser/glic/host/glic_ui.cc
@@ -50,6 +50,11 @@ {"errorNotice", IDS_GLIC_ERROR_NOTICE}, {"errorNoticeActionButton", IDS_GLIC_ERROR_NOTICE_ACTION_BUTTON}, {"errorNoticeHeader", IDS_GLIC_ERROR_NOTICE_HEADER}, + {"ineligibleProfileNotice", IDS_GLIC_INELIGIBLE_PROFILE_NOTICE}, + {"ineligibleProfileNoticeActionButton", + IDS_GLIC_INELIGIBLE_PROFILE_NOTICE_ACTION_BUTTON}, + {"ineligibleProfileNoticeHeader", + IDS_GLIC_INELIGIBLE_PROFILE_NOTICE_HEADER}, {"offlineNoticeAction", IDS_GLIC_OFFLINE_NOTICE_ACTION}, {"offlineNoticeActionButton", IDS_GLIC_OFFLINE_NOTICE_ACTION_BUTTON}, {"offlineNoticeHeader", IDS_GLIC_OFFLINE_NOTICE_HEADER},
diff --git a/chrome/browser/headless/headless_mode_protocol_browsertest.cc b/chrome/browser/headless/headless_mode_protocol_browsertest.cc index b53ee45e..8218e43 100644 --- a/chrome/browser/headless/headless_mode_protocol_browsertest.cc +++ b/chrome/browser/headless/headless_mode_protocol_browsertest.cc
@@ -343,6 +343,9 @@ HEADLESS_MODE_PROTOCOL_TEST(CreateTargetWindowState, "sanity/create-target-window-state.js") +HEADLESS_MODE_PROTOCOL_TEST(DocumentVisibilityState, + "sanity/document-visibility-state.js") + // Headless Mode uses Ozone only when running on Linux. #if BUILDFLAG(IS_LINUX) HEADLESS_MODE_PROTOCOL_TEST_WITH_COMMAND_LINE_EXTRAS(
diff --git a/chrome/browser/headless/test/data/protocol/sanity/document-visibility-state-expected.txt b/chrome/browser/headless/test/data/protocol/sanity/document-visibility-state-expected.txt new file mode 100644 index 0000000..31f37dc60 --- /dev/null +++ b/chrome/browser/headless/test/data/protocol/sanity/document-visibility-state-expected.txt
@@ -0,0 +1,2 @@ +Tests document.visibilityState upon start. +document.visibilityState: visible \ No newline at end of file
diff --git a/chrome/browser/headless/test/data/protocol/sanity/document-visibility-state.js b/chrome/browser/headless/test/data/protocol/sanity/document-visibility-state.js new file mode 100644 index 0000000..6b4a57ab --- /dev/null +++ b/chrome/browser/headless/test/data/protocol/sanity/document-visibility-state.js
@@ -0,0 +1,14 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +(async function(testRunner) { + const {session} = + await testRunner.startBlank('Tests document.visibilityState upon start.'); + + const result = await session.evaluate(`document.visibilityState`); + + testRunner.log('document.visibilityState: ' + result); + + testRunner.completeTest(); +})
diff --git a/chrome/browser/ntp_customization/BUILD.gn b/chrome/browser/ntp_customization/BUILD.gn index b423b1a..3f35d96f 100644 --- a/chrome/browser/ntp_customization/BUILD.gn +++ b/chrome/browser/ntp_customization/BUILD.gn
@@ -22,7 +22,6 @@ "java/src/org/chromium/chrome/browser/ntp_customization/feed/FeedSettingsMediator.java", "java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsCoordinator.java", "java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsListContainerView.java", - "java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsListItemView.java", "java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsMediator.java", ] deps = [ @@ -72,7 +71,7 @@ "java/res/layout/ntp_customization_feed_bottom_sheet.xml", "java/res/layout/ntp_customization_main_bottom_sheet.xml", "java/res/layout/ntp_customization_ntp_cards_bottom_sheet.xml", - "java/res/layout/ntp_customization_ntp_cards_list_item.xml", + "java/res/layout/ntp_customization_ntp_cards_list_item_layout.xml", "java/res/values-night/colors.xml", "java/res/values/colors.xml", "java/res/values/dimens.xml", @@ -102,7 +101,6 @@ "junit/src/org/chromium/chrome/browser/ntp_customization/feed/FeedSettingsMediatorUnitTest.java", "junit/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsCoordinatorUnitTest.java", "junit/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsListContainerViewUnitTest.java", - "junit/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsListItemViewUnitTest.java", "junit/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsMediatorUnitTest.java", ] deps = [
diff --git a/chrome/browser/ntp_customization/java/res/layout/bottom_sheet_list_item_view.xml b/chrome/browser/ntp_customization/java/res/layout/bottom_sheet_list_item_view.xml index aa41819..ec288b1 100644 --- a/chrome/browser/ntp_customization/java/res/layout/bottom_sheet_list_item_view.xml +++ b/chrome/browser/ntp_customization/java/res/layout/bottom_sheet_list_item_view.xml
@@ -7,6 +7,7 @@ <org.chromium.chrome.browser.ntp_customization.BottomSheetListItemView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" android:layout_marginTop="@dimen/ntp_customization_feed_margin_top" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -36,7 +37,7 @@ android:id="@+id/trailing_icon" android:layout_width="@dimen/ntp_customization_bottom_sheet_list_item_icon_size" android:layout_height="@dimen/ntp_customization_bottom_sheet_list_item_icon_size" - android:importantForAccessibility="no" android:layout_marginEnd="@dimen/ntp_customization_edit_icon_margin" - android:layout_marginVertical="@dimen/ntp_customization_edit_icon_margin" /> + android:layout_marginVertical="@dimen/ntp_customization_edit_icon_margin" + tools:ignore="ContentDescription" /> </org.chromium.chrome.browser.ntp_customization.BottomSheetListItemView> \ No newline at end of file
diff --git a/chrome/browser/ntp_customization/java/res/layout/ntp_customization_feed_bottom_sheet.xml b/chrome/browser/ntp_customization/java/res/layout/ntp_customization_feed_bottom_sheet.xml index d0d452a..d26cf14 100644 --- a/chrome/browser/ntp_customization/java/res/layout/ntp_customization_feed_bottom_sheet.xml +++ b/chrome/browser/ntp_customization/java/res/layout/ntp_customization_feed_bottom_sheet.xml
@@ -57,24 +57,18 @@ app:layout_constraintStart_toEndOf="@id/bottom_sheet_title" app:layout_constraintEnd_toEndOf="parent" /> - <LinearLayout - android:id="@+id/feed_switch_button_container" + <org.chromium.components.browser_ui.widget.MaterialSwitchWithText + android:id="@+id/feed_switch_button" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@dimen/ntp_customization_bottom_sheet_layout_padding_bottom" android:layout_marginHorizontal="@dimen/ntp_customization_bottom_sheet_layout_padding_bottom" + android:paddingHorizontal="@dimen/ntp_customization_edit_icon_margin" + tools:baselinealigned="false" app:layout_constraintTop_toBottomOf="@id/bottom_sheet_title" app:layout_constraintStart_toStartOf="parent" - android:background="@drawable/ntp_customization_bottom_sheet_list_item_background_single"> - - <org.chromium.components.browser_ui.widget.MaterialSwitchWithText - android:id="@+id/feed_switch_button" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginHorizontal="@dimen/ntp_customization_edit_icon_margin" - tools:baselinealigned="false" - android:text="@string/text_on" /> - </LinearLayout> + android:background="@drawable/ntp_customization_bottom_sheet_list_item_background_single" + android:text="@string/text_on" /> <TextView android:id="@+id/feed_list_items_title" @@ -85,7 +79,7 @@ android:layout_marginTop="@dimen/ntp_customization_feed_list_items_title_margin_top" android:layout_marginStart="@dimen/ntp_customization_bottom_sheet_layout_padding_bottom" android:layout_marginEnd="@dimen/ntp_customization_edit_icon_margin" - app:layout_constraintTop_toBottomOf="@id/feed_switch_button_container" + app:layout_constraintTop_toBottomOf="@id/feed_switch_button" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" android:text="@string/ntp_customization_feed_list_items_title"/>
diff --git a/chrome/browser/ntp_customization/java/res/layout/ntp_customization_ntp_cards_list_item.xml b/chrome/browser/ntp_customization/java/res/layout/ntp_customization_ntp_cards_list_item.xml deleted file mode 100644 index 5a37ddd..0000000 --- a/chrome/browser/ntp_customization/java/res/layout/ntp_customization_ntp_cards_list_item.xml +++ /dev/null
@@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -Copyright 2025 The Chromium Authors. -Use of this source code is governed by a BSD-style license that can be -found in the LICENSE file. ---> - -<org.chromium.chrome.browser.ntp_customization.ntp_cards.NtpCardsListItemView - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - tools:ignore="UnusedResources" - android:layout_marginTop="@dimen/ntp_customization_feed_margin_top" - android:id="@+id/ntp_cards_list_item" - android:layout_width="match_parent" - android:layout_height="wrap_content"> - - <org.chromium.components.browser_ui.widget.MaterialSwitchWithText - android:id="@+id/ntp_cards_list_item_text_with_switch" - android:layout_width="match_parent" - android:layout_height="wrap_content" - tools:baselinealigned="false" - android:layout_marginHorizontal="@dimen/ntp_customization_edit_icon_margin" /> -</org.chromium.chrome.browser.ntp_customization.ntp_cards.NtpCardsListItemView> \ No newline at end of file
diff --git a/chrome/browser/ntp_customization/java/res/layout/ntp_customization_ntp_cards_list_item_layout.xml b/chrome/browser/ntp_customization/java/res/layout/ntp_customization_ntp_cards_list_item_layout.xml new file mode 100644 index 0000000..0763133 --- /dev/null +++ b/chrome/browser/ntp_customization/java/res/layout/ntp_customization_ntp_cards_list_item_layout.xml
@@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright 2025 The Chromium Authors +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> +<org.chromium.components.browser_ui.widget.MaterialSwitchWithText + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/ntp_cards_list_item_text_with_switch" + android:layout_width="match_parent" + android:layout_height="wrap_content" + tools:baselinealigned="false" + android:layout_marginTop="@dimen/ntp_customization_feed_margin_top" + android:paddingHorizontal="@dimen/ntp_customization_edit_icon_margin" />
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetListContainerView.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetListContainerView.java index 4b95728..776e464 100644 --- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetListContainerView.java +++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetListContainerView.java
@@ -42,6 +42,10 @@ listItemView.setBackground(NtpCustomizationUtils.getBackground(types.size(), i)); listItemView.setTrailingIcon(delegate.getTrailingIcon(type)); listItemView.setOnClickListener(delegate.getListener(type)); + Integer descriptionResId = delegate.getTrailingIconDescriptionResId(type); + if (descriptionResId != null) { + listItemView.setTrailingIconContentDescriptionResId(descriptionResId); + } addView(listItemView); }
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetListItemView.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetListItemView.java index ba04410..816da59 100644 --- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetListItemView.java +++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/BottomSheetListItemView.java
@@ -7,6 +7,7 @@ import android.content.Context; import android.support.annotation.DrawableRes; import android.support.annotation.Nullable; +import android.support.annotation.StringRes; import android.util.AttributeSet; import android.view.View; import android.widget.ImageView; @@ -69,4 +70,9 @@ } mTrailingIcon.setImageResource(resId); } + + /** Sets the content description of the trailing icon besides the title and the subtitle. */ + void setTrailingIconContentDescriptionResId(@StringRes int contentDescription) { + mTrailingIcon.setContentDescription(getResources().getString(contentDescription)); + } }
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ListContainerViewDelegate.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ListContainerViewDelegate.java index 765f07f3..4aab7139 100644 --- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ListContainerViewDelegate.java +++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ListContainerViewDelegate.java
@@ -6,6 +6,7 @@ import android.content.Context; import android.support.annotation.DrawableRes; +import android.support.annotation.StringRes; import android.view.View; import org.chromium.build.annotations.NullMarked; @@ -63,4 +64,14 @@ @Nullable @DrawableRes Integer getTrailingIcon(int type); + + /** + * Returns the resource id for the content description of the list item's trailing icon for the + * given type. + * + * @param type The type of the list item. + */ + @Nullable + @StringRes + Integer getTrailingIconDescriptionResId(int type); }
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationMediator.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationMediator.java index 36da5217..6346565d 100644 --- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationMediator.java +++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationMediator.java
@@ -195,6 +195,11 @@ public @Nullable Integer getTrailingIcon(int type) { return R.drawable.forward_arrow_icon; } + + @Override + public @Nullable Integer getTrailingIconDescriptionResId(int type) { + return R.string.ntp_customization_show_more; + } }; }
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationViewProperties.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationViewProperties.java index 1f5e48f..ef895e1 100644 --- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationViewProperties.java +++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationViewProperties.java
@@ -62,11 +62,16 @@ public static final PropertyModel.WritableBooleanPropertyKey IS_FEED_LIST_ITEMS_TITLE_VISIBLE = new PropertyModel.WritableBooleanPropertyKey(); + public static final PropertyModel.WritableObjectPropertyKey<Integer> + SET_FEED_SWITCH_CONTENT_DESCRIPTION_RES_ID = + new PropertyModel.WritableObjectPropertyKey<>(); + public static final PropertyKey[] FEED_SETTINGS_KEYS = new PropertyKey[] { FEED_SWITCH_ON_CHECKED_CHANGE_LISTENER, IS_FEED_SWITCH_CHECKED, IS_FEED_LIST_ITEMS_TITLE_VISIBLE, - LEARN_MORE_BUTTON_CLICK_LISTENER + LEARN_MORE_BUTTON_CLICK_LISTENER, + SET_FEED_SWITCH_CONTENT_DESCRIPTION_RES_ID }; }
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/feed/FeedSettingsCoordinator.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/feed/FeedSettingsCoordinator.java index 9a337d2..7dab1f2 100644 --- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/feed/FeedSettingsCoordinator.java +++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/feed/FeedSettingsCoordinator.java
@@ -10,6 +10,7 @@ import static org.chromium.chrome.browser.ntp_customization.NtpCustomizationViewProperties.IS_FEED_LIST_ITEMS_TITLE_VISIBLE; import static org.chromium.chrome.browser.ntp_customization.NtpCustomizationViewProperties.IS_FEED_SWITCH_CHECKED; import static org.chromium.chrome.browser.ntp_customization.NtpCustomizationViewProperties.LEARN_MORE_BUTTON_CLICK_LISTENER; +import static org.chromium.chrome.browser.ntp_customization.NtpCustomizationViewProperties.SET_FEED_SWITCH_CONTENT_DESCRIPTION_RES_ID; import android.content.Context; import android.support.annotation.IntDef; @@ -115,6 +116,9 @@ View feedListItemsTitle = view.findViewById(R.id.feed_list_items_title); feedListItemsTitle.setVisibility( model.get(IS_FEED_LIST_ITEMS_TITLE_VISIBLE) ? View.VISIBLE : View.GONE); + } else if (propertyKey == SET_FEED_SWITCH_CONTENT_DESCRIPTION_RES_ID) { + feedSwitch.setTextContentDescriptionResId( + model.get(SET_FEED_SWITCH_CONTENT_DESCRIPTION_RES_ID)); } else if (propertyKey == LEARN_MORE_BUTTON_CLICK_LISTENER) { ImageView learnMoreButton = view.findViewById(R.id.learn_more_button); learnMoreButton.setOnClickListener(model.get(LEARN_MORE_BUTTON_CLICK_LISTENER));
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/feed/FeedSettingsMediator.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/feed/FeedSettingsMediator.java index e685e4b..ac44c7b 100644 --- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/feed/FeedSettingsMediator.java +++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/feed/FeedSettingsMediator.java
@@ -11,6 +11,7 @@ import static org.chromium.chrome.browser.ntp_customization.NtpCustomizationViewProperties.IS_FEED_SWITCH_CHECKED; import static org.chromium.chrome.browser.ntp_customization.NtpCustomizationViewProperties.LEARN_MORE_BUTTON_CLICK_LISTENER; import static org.chromium.chrome.browser.ntp_customization.NtpCustomizationViewProperties.LIST_CONTAINER_VIEW_DELEGATE; +import static org.chromium.chrome.browser.ntp_customization.NtpCustomizationViewProperties.SET_FEED_SWITCH_CONTENT_DESCRIPTION_RES_ID; import static org.chromium.chrome.browser.ntp_customization.feed.FeedSettingsCoordinator.FeedSettingsBottomSheetSection.ACTIVITY; import static org.chromium.chrome.browser.ntp_customization.feed.FeedSettingsCoordinator.FeedSettingsBottomSheetSection.FOLLOWING; import static org.chromium.chrome.browser.ntp_customization.feed.FeedSettingsCoordinator.FeedSettingsBottomSheetSection.HIDDEN; @@ -106,6 +107,9 @@ FEED_SWITCH_ON_CHECKED_CHANGE_LISTENER, (compoundButton, isChecked) -> onFeedSwitchToggled(isChecked)); mFeedSettingsPropertyModel.set( + SET_FEED_SWITCH_CONTENT_DESCRIPTION_RES_ID, + R.string.ntp_customization_turn_on_feed_settings); + mFeedSettingsPropertyModel.set( LEARN_MORE_BUTTON_CLICK_LISTENER, FeedSettingsMediator::handleLearnMoreClick); if (sPrefChangeRegistarForTest != null) { @@ -177,6 +181,11 @@ public @Nullable Integer getTrailingIcon(int type) { return null; } + + @Override + public @Nullable Integer getTrailingIconDescriptionResId(int type) { + return null; + } }; }
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsListContainerView.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsListContainerView.java index 4c6ec328..a66fe6b 100644 --- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsListContainerView.java +++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsListContainerView.java
@@ -21,10 +21,11 @@ import org.chromium.chrome.browser.ntp_customization.NtpCustomizationMetricsUtils; import org.chromium.chrome.browser.ntp_customization.NtpCustomizationUtils; import org.chromium.chrome.browser.ntp_customization.R; +import org.chromium.components.browser_ui.widget.MaterialSwitchWithText; import java.util.List; -/** The view holding {@link NtpCardsListItemView} in the "New tab page cards" bottom sheet. */ +/** The view which holds a list of items in the "New tab page cards" bottom sheet. */ @NullMarked public class NtpCardsListContainerView extends BottomSheetListContainerView { public NtpCardsListContainerView(Context context, @Nullable AttributeSet attrs) { @@ -43,9 +44,9 @@ for (int i = 0; i < types.size(); i++) { Integer type = types.get(i); - NtpCardsListItemView listItemView = (NtpCardsListItemView) createListItemView(); + MaterialSwitchWithText listItemView = (MaterialSwitchWithText) createListItemView(); - listItemView.setTitle(delegate.getListItemTitle(type, mContext)); + listItemView.setText(delegate.getListItemTitle(type, mContext)); listItemView.setBackground( AppCompatResources.getDrawable( getContext(), NtpCustomizationUtils.getBackground(types.size(), i))); @@ -55,12 +56,12 @@ } } - /** Returns a {@link NtpCardsListItemView}. */ + /** Returns a view representing a single list item in this container. */ @Override @VisibleForTesting protected View createListItemView() { - return LayoutInflater.from(getContext()) - .inflate(R.layout.ntp_customization_ntp_cards_list_item, this, false); + return LayoutInflater.from(mContext) + .inflate(R.layout.ntp_customization_ntp_cards_list_item_layout, this, false); } /** @@ -77,7 +78,7 @@ @VisibleForTesting void setUpSwitch( HomeModulesConfigManager homeModulesConfigManager, - NtpCardsListItemView listItemView, + MaterialSwitchWithText listItemView, int type) { listItemView.setChecked(homeModulesConfigManager.getPrefModuleTypeEnabled(type)); listItemView.setOnCheckedChangeListener( @@ -94,7 +95,7 @@ @Override protected void destroy() { for (int i = 0; i < getChildCount(); i++) { - NtpCardsListItemView child = (NtpCardsListItemView) getChildAt(i); + MaterialSwitchWithText child = (MaterialSwitchWithText) getChildAt(i); child.setOnCheckedChangeListener(null); } }
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsListItemView.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsListItemView.java deleted file mode 100644 index d8a0704..0000000 --- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsListItemView.java +++ /dev/null
@@ -1,66 +0,0 @@ -// Copyright 2025 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.ntp_customization.ntp_cards; - -import android.content.Context; -import android.util.AttributeSet; -import android.widget.CompoundButton; -import android.widget.LinearLayout; - -import org.chromium.build.annotations.NullMarked; -import org.chromium.build.annotations.Nullable; -import org.chromium.chrome.browser.ntp_customization.R; -import org.chromium.components.browser_ui.widget.MaterialSwitchWithText; - -/** - * The list item view within a {@link NtpCardsListContainerView} in the "New tab page cards" bottom - * sheet. - */ -@NullMarked -public class NtpCardsListItemView extends LinearLayout { - private MaterialSwitchWithText mMaterialSwitchWithText; - - public NtpCardsListItemView(Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - mMaterialSwitchWithText = findViewById(R.id.ntp_cards_list_item_text_with_switch); - } - - /** - * Sets the content of the title besides the material switch. - * - * @param title The string besides the material switch. - */ - void setTitle(String title) { - mMaterialSwitchWithText.setText(title); - } - - /** - * Sets the switch to On if is checked and Off otherwise. - * - * @param checked The switch view should be set to On or Off. - */ - void setChecked(boolean checked) { - mMaterialSwitchWithText.setChecked(checked); - } - - /** - * Sets the OnCheckedChangeListener of the material switch. - * - * @see CompoundButton#setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener). - */ - public void setOnCheckedChangeListener( - CompoundButton.@Nullable OnCheckedChangeListener listener) { - mMaterialSwitchWithText.setOnCheckedChangeListener(listener); - } - - void setMaterialSwitchWithTextForTesting(MaterialSwitchWithText switchWithText) { - mMaterialSwitchWithText = switchWithText; - } -}
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsMediator.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsMediator.java index 4488253..7e088fd8 100644 --- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsMediator.java +++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsMediator.java
@@ -76,6 +76,11 @@ public @Nullable Integer getTrailingIcon(int type) { return null; } + + @Override + public @Nullable Integer getTrailingIconDescriptionResId(int type) { + return null; + } }; }
diff --git a/chrome/browser/ntp_customization/junit/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsListContainerViewUnitTest.java b/chrome/browser/ntp_customization/junit/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsListContainerViewUnitTest.java index b420dd69..c32c99a3 100644 --- a/chrome/browser/ntp_customization/junit/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsListContainerViewUnitTest.java +++ b/chrome/browser/ntp_customization/junit/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsListContainerViewUnitTest.java
@@ -43,6 +43,7 @@ import org.chromium.chrome.browser.ntp_customization.ListContainerViewDelegate; import org.chromium.chrome.browser.ntp_customization.NtpCustomizationMetricsUtils; import org.chromium.chrome.browser.ntp_customization.R; +import org.chromium.components.browser_ui.widget.MaterialSwitchWithText; import java.util.List; @@ -52,7 +53,7 @@ @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); @Mock ListContainerViewDelegate mDelegate; - @Mock NtpCardsListItemView mListItemView; + @Mock MaterialSwitchWithText mListItemView; @Captor private ArgumentCaptor<CompoundButton.OnCheckedChangeListener> mOnCheckedChangeListenerCaptor; @@ -99,12 +100,12 @@ // Verifies the title, background, and switch are set. int itemListSize = mListContent.size(); - verify(mListItemView, times(itemListSize)).setTitle(any()); + verify(mListItemView, times(itemListSize)).setText(any()); verify(mListItemView, times(itemListSize)).setBackground(any()); verify(mContainerView, times(itemListSize)) .setUpSwitch( any(HomeModulesConfigManager.class), - any(NtpCardsListItemView.class), + any(MaterialSwitchWithText.class), anyInt()); } @@ -112,7 +113,7 @@ @SmallTest public void testSetUpSwitch() { HomeModulesConfigManager manager = mock(HomeModulesConfigManager.class); - NtpCardsListItemView listItemView = mock(NtpCardsListItemView.class); + MaterialSwitchWithText listItemView = mock(MaterialSwitchWithText.class); String histogramTurnOnName = "NewTabPage.Customization.TurnOnModule"; String histogramTurnOffName = "NewTabPage.Customization.TurnOffModule";
diff --git a/chrome/browser/ntp_customization/junit/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsListItemViewUnitTest.java b/chrome/browser/ntp_customization/junit/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsListItemViewUnitTest.java deleted file mode 100644 index d9a04ed..0000000 --- a/chrome/browser/ntp_customization/junit/src/org/chromium/chrome/browser/ntp_customization/ntp_cards/NtpCardsListItemViewUnitTest.java +++ /dev/null
@@ -1,70 +0,0 @@ -// Copyright 2025 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.ntp_customization.ntp_cards; - -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import android.content.Context; -import android.widget.CompoundButton; - -import androidx.test.core.app.ApplicationProvider; -import androidx.test.filters.SmallTest; - -import org.junit.Before; -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.components.browser_ui.widget.MaterialSwitchWithText; - -/** Unit tests for {@link NtpCardsListItemView}. */ -@RunWith(BaseRobolectricTestRunner.class) -public class NtpCardsListItemViewUnitTest { - @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); - - @Mock private MaterialSwitchWithText mMaterialSwitchWithText; - - private NtpCardsListItemView mListView; - - @Before - public void setUp() { - Context context = ApplicationProvider.getApplicationContext(); - mListView = new NtpCardsListItemView(context, null); - mListView.setMaterialSwitchWithTextForTesting(mMaterialSwitchWithText); - } - - @Test - @SmallTest - public void testSetTitle() { - String text = "New tab page cards"; - mListView.setTitle(text); - verify(mMaterialSwitchWithText).setText(text); - } - - @Test - @SmallTest - public void testSetChecked() { - mListView.setChecked(false); - verify(mMaterialSwitchWithText).setChecked(eq(false)); - - mListView.setChecked(true); - verify(mMaterialSwitchWithText).setChecked(eq(true)); - } - - @Test - @SmallTest - public void testSetOnCheckedChangeListener() { - CompoundButton.OnCheckedChangeListener listener = - mock(CompoundButton.OnCheckedChangeListener.class); - mListView.setOnCheckedChangeListener(listener); - verify(mMaterialSwitchWithText).setOnCheckedChangeListener(eq(listener)); - } -}
diff --git a/chrome/browser/platform_experience/installer/installer_win.cc b/chrome/browser/platform_experience/installer/installer_win.cc index 4181c07..4254948 100644 --- a/chrome/browser/platform_experience/installer/installer_win.cc +++ b/chrome/browser/platform_experience/installer/installer_win.cc
@@ -8,6 +8,7 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/logging.h" +#include "base/metrics/histogram_functions.h" #include "base/path_service.h" #include "base/process/launch.h" #include "base/win/scoped_variant.h" @@ -19,11 +20,11 @@ namespace { // Switch used to install platform_experience_helper -const char kPlatformExperienceHelperForceInstallSwitch[] = "force-install"; +constexpr char kPlatformExperienceHelperForceInstallSwitch[] = "force-install"; // Directory under which platform_experience_helper is installed -const wchar_t kPlatformExperienceHelperDir[] = L"PlatformExperienceHelper"; +constexpr wchar_t kPlatformExperienceHelperDir[] = L"PlatformExperienceHelper"; // Name of the platform_experience_helper executable -const wchar_t kPlatformExperienceHelperExe[] = +constexpr wchar_t kPlatformExperienceHelperExe[] = L"platform_experience_helper.exe"; // This function might block. @@ -41,6 +42,43 @@ return base::PathExists(peh_exe_path); } +// Enum for tracking the launch status of the platform experience helper +// installer for system installs. +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. +// LINT.IfChange(SystemInstallerLaunchStatus) +enum class SystemInstallerLaunchStatus { + kSuccess = 0, + kAppCommandNotFound = 1, + kAppCommandExecutionFailed = 2, + kMaxValue = kAppCommandExecutionFailed, +}; +// LINT.ThenChange(//tools/metrics/histograms/metadata/windows/enums.xml:SystemInstallerLaunchStatus) + +// Enum for tracking the launch status of the platform experience helper +// installer for user installs. +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. +// LINT.IfChange(UserInstallerLaunchStatus) +enum class UserInstallerLaunchStatus { + kSuccess = 0, + kFileNotFound = 1, + kAccessDenied = 2, + kOtherFailure = 3, + kMaxValue = kOtherFailure, +}; +// LINT.ThenChange(//tools/metrics/histograms/metadata/windows/enums.xml:UserInstallerLaunchStatus) + +void ReportSystemInstallerLaunchStatus(SystemInstallerLaunchStatus status) { + base::UmaHistogramEnumeration( + "Windows.PlatformExperienceHelper.InstallerLaunchStatus.System", status); +} + +void ReportUserInstallLaunchStatusMetric(UserInstallerLaunchStatus status) { + base::UmaHistogramEnumeration( + "Windows.PlatformExperienceHelper.InstallerLaunchStatus.User", status); +} + } // namespace namespace platform_experience { @@ -50,16 +88,22 @@ return; } - // TODO(crbug.com/422447800): Report metrics for number of installer launch - // attempts (success vs. failure), split by user vs system installs. if (install_static::IsSystemInstall()) { auto command = GetUpdaterAppCommand(installer::kCmdInstallPEH); if (!command.has_value()) { + ReportSystemInstallerLaunchStatus( + SystemInstallerLaunchStatus::kAppCommandNotFound); return; } const VARIANT& var = base::win::ScopedVariant::kEmptyVariant; - (*command)->execute(var, var, var, var, var, var, var, var, var); + if (FAILED( + (*command)->execute(var, var, var, var, var, var, var, var, var))) { + ReportSystemInstallerLaunchStatus( + SystemInstallerLaunchStatus::kAppCommandExecutionFailed); + } else { + ReportSystemInstallerLaunchStatus(SystemInstallerLaunchStatus::kSuccess); + } return; } @@ -75,10 +119,21 @@ launch_options.force_breakaway_from_job_ = true; ::SetLastError(ERROR_SUCCESS); base::Process process = base::LaunchProcess(install_cmd, launch_options); + UserInstallerLaunchStatus status = UserInstallerLaunchStatus::kSuccess; if (!process.IsValid()) { - PLOG(ERROR) << "Failed to launch \"" << install_cmd.GetCommandLineString() - << "\""; + switch (::GetLastError()) { + case ERROR_FILE_NOT_FOUND: + status = UserInstallerLaunchStatus::kFileNotFound; + break; + case ERROR_ACCESS_DENIED: + status = UserInstallerLaunchStatus::kAccessDenied; + break; + default: + status = UserInstallerLaunchStatus::kOtherFailure; + break; + } } + ReportUserInstallLaunchStatusMetric(status); } } // namespace platform_experience
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java index 92ce59d..1c016cb 100644 --- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java +++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
@@ -422,6 +422,11 @@ public static final String MULTI_WINDOW_START_TIME = "Chrome.MultiWindow.StartTime"; public static final String MULTI_INSTANCE_CLOSE_WINDOW_SKIP_CONFIRM = "Chrome.MultiWindow.CloseWindowSkipConfirm"; + + public static final String MULTI_INSTANCE_MAX_INSTANCE_LIMIT = + "Chrome.MultiWindow.MaxInstanceLimit"; + public static final String MULTI_INSTANCE_INSTANCE_LIMIT_DOWNGRADE_TRIGGERED = + "Chrome.MultiWindow.InstanceLimitDowngradeTriggered"; public static final String MULTI_INSTANCE_RESTORATION_MESSAGE_SHOWN = "Chrome.MultiWindow.RestorationMessageShown"; @@ -1062,6 +1067,8 @@ LOCALE_MANAGER_PROMO_V3_CHECKED, MULTI_WINDOW_START_TIME, MULTI_INSTANCE_CLOSE_WINDOW_SKIP_CONFIRM, + MULTI_INSTANCE_MAX_INSTANCE_LIMIT, + MULTI_INSTANCE_INSTANCE_LIMIT_DOWNGRADE_TRIGGERED, MULTI_INSTANCE_RESTORATION_MESSAGE_SHOWN, MULTI_INSTANCE_IS_INCOGNITO_SELECTED.pattern(), MULTI_INSTANCE_INCOGNITO_TAB_COUNT.pattern(),
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerCoordinator.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerCoordinator.java index a33280cf..dfa6b5c 100644 --- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerCoordinator.java +++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerCoordinator.java
@@ -122,7 +122,7 @@ public void playTabRequested(PlaybackMode playbackMode) { mMediator.setPlayback(null); mMediator.setRequestedPlaybackMode(playbackMode); - mMediator.setPlaybackState(PlaybackListener.State.BUFFERING); + mMediator.setPlaybackState(PlaybackListener.State.PLAYBACK_CREATION); if (!mExpandedPlayer.anySheetShowing()) { mMiniPlayer.show(/* animate= */ true); }
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerCoordinatorUnitTest.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerCoordinatorUnitTest.java index 1b11428b..dc1fe2a 100644 --- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerCoordinatorUnitTest.java +++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerCoordinatorUnitTest.java
@@ -127,7 +127,7 @@ // Mini player shows in buffering state verify(mMediator).setPlayback(eq(null)); - verify(mMediator).setPlaybackState(eq(PlaybackListener.State.BUFFERING)); + verify(mMediator).setPlaybackState(eq(PlaybackListener.State.PLAYBACK_CREATION)); verify(mMediator).setRequestedPlaybackMode(PlaybackMode.OVERVIEW); verify(mMiniPlayer).show(eq(true)); } @@ -139,7 +139,7 @@ // Mini player is not shown. verify(mMediator).setPlayback(eq(null)); - verify(mMediator).setPlaybackState(eq(PlaybackListener.State.BUFFERING)); + verify(mMediator).setPlaybackState(eq(PlaybackListener.State.PLAYBACK_CREATION)); verify(mMiniPlayer, never()).show(anyBoolean()); } @@ -147,7 +147,7 @@ public void testPlaybackReady() { mPlayerCoordinator.playTabRequested(PlaybackMode.UNSPECIFIED); verify(mMediator).setPlayback(eq(null)); - verify(mMediator).setPlaybackState(eq(PlaybackListener.State.BUFFERING)); + verify(mMediator).setPlaybackState(eq(PlaybackListener.State.PLAYBACK_CREATION)); reset(mMediator); mPlayerCoordinator.playbackReady(mPlayback, PlaybackListener.State.PLAYING); @@ -159,7 +159,7 @@ public void testPlaybackFailed() { mPlayerCoordinator.playTabRequested(PlaybackMode.UNSPECIFIED); verify(mMediator).setPlayback(eq(null)); - verify(mMediator).setPlaybackState(eq(PlaybackListener.State.BUFFERING)); + verify(mMediator).setPlaybackState(eq(PlaybackListener.State.PLAYBACK_CREATION)); reset(mMediator); mPlayerCoordinator.playbackFailed(); @@ -192,7 +192,7 @@ public void testDismissPlayers() { mPlayerCoordinator.playTabRequested(PlaybackMode.UNSPECIFIED); verify(mMediator).setPlayback(eq(null)); - verify(mMediator).setPlaybackState(eq(PlaybackListener.State.BUFFERING)); + verify(mMediator).setPlaybackState(eq(PlaybackListener.State.PLAYBACK_CREATION)); reset(mMediator); mPlayerCoordinator.dismissPlayers(); @@ -206,7 +206,7 @@ public void testDismissPlayers_restorablePlayer() { mPlayerCoordinator.playTabRequested(PlaybackMode.UNSPECIFIED); verify(mMediator).setPlayback(eq(null)); - verify(mMediator).setPlaybackState(eq(PlaybackListener.State.BUFFERING)); + verify(mMediator).setPlaybackState(eq(PlaybackListener.State.PLAYBACK_CREATION)); reset(mMediator); doReturn(true).when(mMediator).isPlayerRestorable();
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerMediator.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerMediator.java index 119f98b9..e12b4f0 100644 --- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerMediator.java +++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerMediator.java
@@ -8,6 +8,7 @@ import static org.chromium.chrome.modules.readaloud.PlaybackListener.State.BUFFERING; import static org.chromium.chrome.modules.readaloud.PlaybackListener.State.ERROR; import static org.chromium.chrome.modules.readaloud.PlaybackListener.State.PAUSED; +import static org.chromium.chrome.modules.readaloud.PlaybackListener.State.PLAYBACK_CREATION; import static org.chromium.chrome.modules.readaloud.PlaybackListener.State.PLAYING; import static org.chromium.chrome.modules.readaloud.PlaybackListener.State.STOPPED; @@ -430,7 +431,7 @@ public void onShouldRestoreMiniPlayer() { @PlaybackListener.State int state = mModel.get(PlayerProperties.PLAYBACK_STATE); // TODO(b/352563278): All player UI should be made to work without a playback. - if (mPlayback != null || state == ERROR || state == BUFFERING) { + if (mPlayback != null || state == ERROR || state == BUFFERING || state == PLAYBACK_CREATION) { mCoordinator.restoreMiniPlayer(); } }
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerMediatorUnitTest.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerMediatorUnitTest.java index c9b123a..56db918 100644 --- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerMediatorUnitTest.java +++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/PlayerMediatorUnitTest.java
@@ -22,6 +22,7 @@ import static org.chromium.chrome.modules.readaloud.PlaybackListener.State.BUFFERING; import static org.chromium.chrome.modules.readaloud.PlaybackListener.State.ERROR; import static org.chromium.chrome.modules.readaloud.PlaybackListener.State.PAUSED; +import static org.chromium.chrome.modules.readaloud.PlaybackListener.State.PLAYBACK_CREATION; import static org.chromium.chrome.modules.readaloud.PlaybackListener.State.PLAYING; import static org.chromium.chrome.modules.readaloud.PlaybackListener.State.STOPPED; import static org.chromium.chrome.modules.readaloud.PlaybackListener.State.UNKNOWN; @@ -818,6 +819,25 @@ } @Test + public void testShouldRestoreMiniPlayer_playbackCreation() { + // Set playback state through playback update, as if the error happened during playback. + mMediator.setPlayback(mPlayback); + verify(mPlayback).addListener(mPlaybackListenerCaptor.capture()); + + mPlaybackData.mState = PLAYBACK_CREATION; + mPlaybackListenerCaptor.getValue().onPlaybackDataChanged(mPlaybackData); + + assertEquals(PLAYBACK_CREATION, (int) mModel.get(PlayerProperties.PLAYBACK_STATE)); + + // Clear playback. + mMediator.setPlayback(null); + + // The mini player should restore. + mMediator.onShouldRestoreMiniPlayer(); + verify(mPlayerCoordinator).restoreMiniPlayer(); + } + + @Test public void testShouldRestoreMiniPlayer() { mMediator.setPlayback(mPlayback); mMediator.onShouldRestoreMiniPlayer();
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContent.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContent.java index 639acc3c0..447b24d1 100644 --- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContent.java +++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContent.java
@@ -193,7 +193,7 @@ case PlaybackListener.State.ERROR: showErrorLayout(); break; - case PlaybackListener.State.BUFFERING: + case PlaybackListener.State.PLAYBACK_CREATION: showLoadingLayout(); break; default:
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContentUnitTest.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContentUnitTest.java index 7780fa56..d13e8f2 100644 --- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContentUnitTest.java +++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContentUnitTest.java
@@ -79,6 +79,7 @@ private Activity mActivity; private LinearLayout mNormalLayout; private LinearLayout mErrorLayout; + private LinearLayout mLoadingLayout; private ImageView mThumbUp; private ImageView mThumbDown; private ImageView mMoreOptions; @@ -108,6 +109,7 @@ mSeekbar = (SeekBar) mContentView.findViewById(R.id.readaloud_expanded_player_seek_bar); mNormalLayout = (LinearLayout) mContentView.findViewById(R.id.normal_layout); mErrorLayout = (LinearLayout) mContentView.findViewById(R.id.error_layout); + mLoadingLayout = (LinearLayout) mContentView.findViewById(R.id.readaloud_loading_overlay); mThumbUp = (ImageView) mContentView.findViewById(R.id.readaloud_thumb_up_button); mThumbDown = (ImageView) mContentView.findViewById(R.id.readaloud_thumb_down_button); mMoreOptions = (ImageView) mContentView.findViewById(R.id.readaloud_more_button); @@ -336,6 +338,14 @@ assertEquals(loadingText.getText(), mContext.getString(R.string.readaloud_playback_loading)); } + @Test + public void testLoadingLayoutIsShownInPlaybackCreation() { + mContent.onPlaybackStateChanged(PlaybackListener.State.PLAYBACK_CREATION); + + assertTrue(mErrorLayout.getVisibility() == View.GONE); + assertTrue(mLoadingLayout.getVisibility() == View.VISIBLE); + } + @Test public void testFormatDuration() {
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerLayout.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerLayout.java index 17729225..4d5dd30 100644 --- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerLayout.java +++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerLayout.java
@@ -8,6 +8,7 @@ import static org.chromium.chrome.modules.readaloud.PlaybackListener.State.ERROR; import static org.chromium.chrome.modules.readaloud.PlaybackListener.State.PAUSED; import static org.chromium.chrome.modules.readaloud.PlaybackListener.State.PLAYING; +import static org.chromium.chrome.modules.readaloud.PlaybackListener.State.PLAYBACK_CREATION; import static org.chromium.chrome.modules.readaloud.PlaybackListener.State.STOPPED; import static org.chromium.chrome.modules.readaloud.PlaybackListener.State.UNKNOWN; @@ -236,6 +237,7 @@ void onPlaybackStateChanged(@PlaybackListener.State int state) { switch (state) { // UNKNOWN is currently the "reset" state and can be treated same as buffering. + case PLAYBACK_CREATION: case BUFFERING: case UNKNOWN: showBufferingLayout();
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerLayoutUnitTest.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerLayoutUnitTest.java index 004f4c7..36d6538b 100644 --- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerLayoutUnitTest.java +++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerLayoutUnitTest.java
@@ -85,6 +85,17 @@ } @Test + public void testBufferingWhenCreatingPlayback() { + mLayout.onPlaybackStateChanged(PlaybackListener.State.PLAYBACK_CREATION); + assertEquals(View.GONE, mLayout.findViewById(R.id.progress_bar).getVisibility()); + + // Only the buffering layout is visible. + assertEquals(View.VISIBLE, mLayout.findViewById(R.id.buffering_layout).getVisibility()); + assertEquals(View.GONE, mLayout.findViewById(R.id.normal_layout).getVisibility()); + assertEquals(View.GONE, mLayout.findViewById(R.id.error_layout).getVisibility()); + } + + @Test public void testBufferingStrings() { mLayout.setRequestedPlaybackMode(PlaybackMode.OVERVIEW); mLayout.onPlaybackStateChanged(PlaybackListener.State.BUFFERING);
diff --git a/chrome/browser/resources/glic/glic.html b/chrome/browser/resources/glic/glic.html index b08f43f..9edf1491 100644 --- a/chrome/browser/resources/glic/glic.html +++ b/chrome/browser/resources/glic/glic.html
@@ -63,8 +63,11 @@ </cr-icon-button> </div> <div class="notice"> - <div class="icon"><cr-icon icon="glic:error"></cr-icon></div> - <p class="headline">$i18n{errorNoticeHeader}</p> + <div class="icon"><cr-icon icon="glic:person-alert"></cr-icon></div> + <p class="headline">$i18n{ineligibleProfileNoticeHeader}</p> + <p>$i18n{ineligibleProfileNotice}</p> + <cr-button class="tonal-button" id="profilePickerButton" + role="button">$i18n{ineligibleProfileNoticeActionButton}</cr-button> </div> </div> </section>
diff --git a/chrome/browser/resources/glic/glic_app_controller.ts b/chrome/browser/resources/glic/glic_app_controller.ts index ae67b0c0..782b9834 100644 --- a/chrome/browser/resources/glic/glic_app_controller.ts +++ b/chrome/browser/resources/glic/glic_app_controller.ts
@@ -45,6 +45,7 @@ guestPanel: HTMLElement; webviewHeader: HTMLDivElement; webviewContainer: HTMLDivElement; + profilePickerButton: HTMLButtonElement; signInButton: HTMLButtonElement; unresponsiveOverlay: HTMLElement; } @@ -130,6 +131,9 @@ } else { this.setState(WebUiState.kOffline); } + $.profilePickerButton.addEventListener('click', () => { + this.openProfilePicker(); + }); $.signInButton.addEventListener('click', () => { this.signIn(); }); @@ -350,6 +354,7 @@ const readyState = this.profileReadyState; switch (readyState) { + case ProfileReadyState.kIneligible: case ProfileReadyState.kUnknownError: this.setState(WebUiState.kUnavailable); return; @@ -575,6 +580,10 @@ this.setState(WebUiState.kBeginLoad); } + private openProfilePicker(): void { + this.browserProxy.handler.openProfilePickerAndClosePanel(); + } + private signIn(): void { this.browserProxy.handler.signInAndClosePanel(); }
diff --git a/chrome/browser/resources/lens/overlay/lens_overlay_app.html b/chrome/browser/resources/lens/overlay/lens_overlay_app.html index e8e9f394..057ab69 100644 --- a/chrome/browser/resources/lens/overlay/lens_overlay_app.html +++ b/chrome/browser/resources/lens/overlay/lens_overlay_app.html
@@ -328,11 +328,20 @@ /* Colors for searchbox ghost loader */ --color-searchbox-ghost-loader-loading-bar-1: #F1F3F4; --color-searchbox-ghost-loader-loading-bar-2: #ECEDEF; + /* The size of the searchbox container doesn't match the searchbox and ghost + loader, so don't allow pointer events on the searchbox container. Only + allow pointer events on the searchbox and ghost loader. */ + pointer-events: none; position: absolute; inset-block-start: 40px; inset-inline-end: 140px; } + #searchboxContainer > * { + /* Allow pointer events on the searchbox and ghost loader. */ + pointer-events: all; + } + :host(:not([is-translate-button-enabled])) #searchboxContainer { inset-inline-end: 84px; }
diff --git a/chrome/browser/resources/lens/shared/searchbox_ghost_loader.html b/chrome/browser/resources/lens/shared/searchbox_ghost_loader.html index 92d8f83..b200b20 100644 --- a/chrome/browser/resources/lens/shared/searchbox_ghost_loader.html +++ b/chrome/browser/resources/lens/shared/searchbox_ghost_loader.html
@@ -31,31 +31,28 @@ padding-top: 4px; } -#loadingState.status-container { - padding-inline-start: 16px; -} - :host([enable-csb-motion-tweaks]) #loadingState.status-container { display: none; } .loader-text { - position: absolute; - padding-inline-start: 38px; - padding-inline-end: 14px; font-weight: var(--cr-searchbox-match-font-weight); font-size: 14px; - width: 234px; -} - -#loadingState .loader-text { - padding-inline-start: 36px; + position: relative; + width: 100%; } #hint-text2 { opacity: 0; } +.hint-text { + align-items: center; + display: flex; + inset: 0; + position: absolute; +} + :host([enable-summarize-suggestion-hint]) #hint-text1 { animation: flipText 6s ease-in-out infinite; } @@ -82,6 +79,11 @@ .spinner { --cr-spinner-color: var(--color-searchbox-ghost-loader-spinner); --cr-spinner-size: 20px; + align-items: center; + display: flex; + justify-content: center; + /* 28px to match the error icon size. */ + width: 28px; } .suggestion-loader-container { @@ -166,6 +168,7 @@ :host([show-error-state]) #errorState, #hintState { display: flex; + gap: 16px; } :host([show-error-state]) #loadingState, @@ -215,12 +218,14 @@ <template is="dom-if" if="[[showContextualSearchboxLoadingState]]"> <div id="loadingState" class="status-container"> <div class="spinner"></div> - <span id="hint-text1" class="loader-text"> - [[ghostLoaderPrimaryMessage]] - </span> - <span id="hint-text2" class="loader-text"> - $i18n{searchboxGhostLoaderHintTextSecondary} - </span> + <div class="loader-text"> + <span id="hint-text1" class="hint-text"> + [[ghostLoaderPrimaryMessage]] + </span> + <span id="hint-text2" class="hint-text"> + $i18n{searchboxGhostLoaderHintTextSecondary} + </span> + </div> </div> <div class="suggestion-loader-container"> <template is="dom-repeat"
diff --git a/chrome/browser/resources/new_tab_footer/app.css b/chrome/browser/resources/new_tab_footer/app.css index 956444a..7682afd4 100644 --- a/chrome/browser/resources/new_tab_footer/app.css +++ b/chrome/browser/resources/new_tab_footer/app.css
@@ -91,7 +91,12 @@ border-radius: 8px; } +#managementNoticeLogoContainer > cr-icon, #managementNoticeLogoContainer > img { width: 20px; height: 20px; +} + +cr-icon { + --iron-icon-fill-color: var(--color-new-tab-footer-text); } \ No newline at end of file
diff --git a/chrome/browser/resources/new_tab_footer/app.html.ts b/chrome/browser/resources/new_tab_footer/app.html.ts index 85fcdc3..7605328 100644 --- a/chrome/browser/resources/new_tab_footer/app.html.ts +++ b/chrome/browser/resources/new_tab_footer/app.html.ts
@@ -19,10 +19,13 @@ html`<div id="managementNoticeContainer" class="notice-item" title="${this.managementNotice_.text}"> <div id="managementNoticeLogoContainer" - class=${this.managementNotice_.isCustomLogo ? + class=${this.managementNotice_.customBitmapDataUrl ? 'custom_logo' : ''}> - <img id="managementNoticeLogo" alt="" - src="${this.managementNotice_.bitmapDataUrl.url}"> + ${this.managementNotice_.customBitmapDataUrl ? html` + <img id="managementNoticeLogo" alt="" + src="${this.managementNotice_.customBitmapDataUrl.url}">`: html` + <cr-icon icon="cr:domain" alt="" id="managementNoticeLogo" > + </cr-icon>`} </div> <button @click="${this.onManagementNoticeClick_}" role="link" aria-label="${this.managementNotice_.text}"
diff --git a/chrome/browser/resources/new_tab_footer/app.ts b/chrome/browser/resources/new_tab_footer/app.ts index 5f40378..5c92b73 100644 --- a/chrome/browser/resources/new_tab_footer/app.ts +++ b/chrome/browser/resources/new_tab_footer/app.ts
@@ -4,6 +4,8 @@ import '/strings.m.js'; import 'chrome://newtab-footer/shared/customize_buttons/customize_buttons.js'; +import 'chrome://resources/cr_elements/cr_icon/cr_icon.js'; +import 'chrome://resources/cr_elements/icons.html.js'; import {ColorChangeUpdater} from 'chrome://resources/cr_components/color_change_listener/colors_css_updater.js'; import {assert} from 'chrome://resources/js/assert.js';
diff --git a/chrome/browser/resources/settings/appearance_page/appearance_page.ts b/chrome/browser/resources/settings/appearance_page/appearance_page.ts index 6554e94..b58c7905 100644 --- a/chrome/browser/resources/settings/appearance_page/appearance_page.ts +++ b/chrome/browser/resources/settings/appearance_page/appearance_page.ts
@@ -30,6 +30,7 @@ import type {DropdownMenuOptionList, SettingsDropdownMenuElement} from '../controls/settings_dropdown_menu.js'; import type {SettingsToggleButtonElement} from '../controls/settings_toggle_button.js'; import {loadTimeData} from '../i18n_setup.js'; +import {pageVisibility} from '../page_visibility.js'; import type {AppearancePageVisibility} from '../page_visibility.js'; import {RelaunchMixin, RestartType} from '../relaunch_mixin.js'; import {routes} from '../route.js'; @@ -100,7 +101,10 @@ /** * Dictionary defining page visibility. */ - pageVisibility: Object, + pageVisibility_: { + type: Object, + value: () => pageVisibility?.appearance, + }, defaultZoom_: Number, @@ -269,7 +273,7 @@ ]; } - declare pageVisibility: AppearancePageVisibility; + declare private pageVisibility_?: AppearancePageVisibility; declare private defaultZoom_: number; declare private isWallpaperPolicyControlled_: boolean; declare private fontSizeOptions_: DropdownMenuOptionList;
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.html b/chrome/browser/resources/settings/basic_page/basic_page.html index 779a0a76..3e5e2c80 100644 --- a/chrome/browser/resources/settings/basic_page/basic_page.html +++ b/chrome/browser/resources/settings/basic_page/basic_page.html
@@ -26,15 +26,13 @@ <settings-reset-profile-banner on-close="onResetProfileBannerClosed_"> </settings-reset-profile-banner> </template> - <template is="dom-if" if="[[showPage_(pageVisibility.people)]]" restamp> + <template is="dom-if" if="[[showPage_(pageVisibility_.people)]]" restamp> <settings-section page-title="$i18n{peoplePageTitle}" section="people"> - <settings-people-page prefs="{{prefs}}" - page-visibility="[[pageVisibility]]"> - </settings-people-page> + <settings-people-page prefs="{{prefs}}"></settings-people-page> </settings-section> </template> - <template is="dom-if" if="[[showAiPage_(pageVisibility.ai)]]" restamp> + <template is="dom-if" if="[[showAiPage_(pageVisibility_.ai)]]" restamp> <settings-section section="aiInfoCard" nest-under-section="ai"> <settings-ai-info-card></settings-ai-info-card> </settings-section> @@ -53,7 +51,7 @@ </settings-section> </template> </template> - <template is="dom-if" if="[[showPage_(pageVisibility.autofill)]]" + <template is="dom-if" if="[[showPage_(pageVisibility_.autofill)]]" restamp> <settings-section page-title="$i18n{autofillPageTitle}" section="autofill"> @@ -70,7 +68,7 @@ <!-- TODO(crbug.com/40267370): Add a test to basic_page_test.ts to check that settings-safety-hub-entry-point is not visible in the guest mode. --> - <template is="dom-if" if="[[showPage_(pageVisibility.safetyHub)]]" + <template is="dom-if" if="[[showPage_(pageVisibility_.safetyHub)]]" restamp> <settings-section page-title="$i18n{safetyHub}" section="safetyHubEntryPoint" nest-under-section="privacy" @@ -78,17 +76,16 @@ <settings-safety-hub-entry-point></settings-safety-hub-entry-point> </settings-section> </template> - <template is="dom-if" if="[[showPage_(pageVisibility.privacy)]]" + <template is="dom-if" if="[[showPage_(pageVisibility_.privacy)]]" restamp> <settings-section page-title="$i18n{privacyPageTitle}" section="privacy"> - <settings-privacy-page prefs="{{prefs}}" - page-visibility="[[pageVisibility.privacy]]"> + <settings-privacy-page prefs="{{prefs}}"> </settings-privacy-page> </settings-section> </template> <template is="dom-if" - if="[[showPage_(pageVisibility.performance)]]" + if="[[showPage_(pageVisibility_.performance)]]" restamp> <settings-section page-title="$i18n{generalPageTitle}" section="performance" id="performanceSettingsSection" @@ -133,12 +130,11 @@ <settings-speed-page prefs="{{prefs}}"></settings-speed-page> </settings-section> </template> - <template is="dom-if" if="[[showPage_(pageVisibility.appearance)]]" + <template is="dom-if" if="[[showPage_(pageVisibility_.appearance)]]" restamp> <settings-section page-title="$i18n{appearancePageTitle}" section="appearance"> - <settings-appearance-page prefs="{{prefs}}" - page-visibility="[[pageVisibility.appearance]]"> + <settings-appearance-page prefs="{{prefs}}"> </settings-appearance-page> </settings-section> </template> @@ -147,7 +143,7 @@ <settings-search-page prefs="{{prefs}}"></settings-search-page> </settings-section> <if expr="not is_chromeos"> - <template is="dom-if" if="[[showPage_(pageVisibility.defaultBrowser)]]" + <template is="dom-if" if="[[showPage_(pageVisibility_.defaultBrowser)]]" restamp> <settings-section page-title="$i18n{defaultBrowser}" section="defaultBrowser"> @@ -155,7 +151,7 @@ </settings-section> </template> </if> - <template is="dom-if" if="[[showPage_(pageVisibility.onStartup)]]" + <template is="dom-if" if="[[showPage_(pageVisibility_.onStartup)]]" restamp> <settings-section page-title="$i18n{onStartup}" section="onStartup"> <settings-on-startup-page prefs="{{prefs}}"> @@ -165,11 +161,11 @@ </div> </template> <template is="dom-if" - if="[[showAdvancedSettings_(pageVisibility.advancedSettings)]]"> + if="[[showAdvancedSettings_(pageVisibility_.advancedSettings)]]"> <settings-idle-load id="advancedPageTemplate"> <template> <div id="advancedPage"> - <template is="dom-if" if="[[showPage_(pageVisibility.languages)]]" + <template is="dom-if" if="[[showPage_(pageVisibility_.languages)]]" restamp> <if expr="not chromeos_ash"> <settings-languages languages="{{languages}}" prefs="{{prefs}}" @@ -199,7 +195,7 @@ </settings-section> </template> <if expr="not chromeos_ash"> - <template is="dom-if" if="[[showPage_(pageVisibility.spellCheck)]]" + <template is="dom-if" if="[[showPage_(pageVisibility_.spellCheck)]]" restamp> <settings-section page-title="$i18n{spellCheckTitle}" section="spellCheck" nest-under-section="languages" @@ -218,7 +214,7 @@ </settings-translate-page> </settings-section> </if> - <template is="dom-if" if="[[showPage_(pageVisibility.downloads)]]" + <template is="dom-if" if="[[showPage_(pageVisibility_.downloads)]]" restamp> <settings-section page-title="$i18n{downloadsPageTitle}" section="downloads"> @@ -226,7 +222,7 @@ </settings-downloads-page> </settings-section> </template> - <template is="dom-if" if="[[showPage_(pageVisibility.a11y)]]" + <template is="dom-if" if="[[showPage_(pageVisibility_.a11y)]]" restamp> <settings-section page-title="$i18n{a11yPageTitle}" section="a11y"> @@ -242,7 +238,7 @@ <settings-system-page prefs="{{prefs}}"></settings-system-page> </settings-section> </if> - <template is="dom-if" if="[[showPage_(pageVisibility.reset)]]" + <template is="dom-if" if="[[showPage_(pageVisibility_.reset)]]" restamp> <settings-section page-title="$i18n{resetPageTitle}" section="reset">
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.ts b/chrome/browser/resources/settings/basic_page/basic_page.ts index 1aa8d73..f3a3166 100644 --- a/chrome/browser/resources/settings/basic_page/basic_page.ts +++ b/chrome/browser/resources/settings/basic_page/basic_page.ts
@@ -57,6 +57,7 @@ // <if expr="not chromeos_ash"> import type {LanguageHelper, LanguagesModel} from '../languages_page/languages_types.js'; // </if> +import {pageVisibility} from '../page_visibility.js'; import type {PageVisibility} from '../page_visibility.js'; import type {PerformanceBrowserProxy} from '../performance_page/performance_browser_proxy.js'; import {PerformanceBrowserProxyImpl, PerformanceFeedbackCategory} from '../performance_page/performance_browser_proxy.js'; @@ -100,10 +101,10 @@ /** * Dictionary defining page visibility. */ - pageVisibility: { + pageVisibility_: { type: Object, value() { - return {}; + return pageVisibility || {}; }, }, @@ -180,7 +181,7 @@ declare languages?: LanguagesModel; declare languageHelper: LanguageHelper; // </if> - declare pageVisibility: PageVisibility; + declare private pageVisibility_: PageVisibility; declare inSearchMode: boolean; declare private showResetProfileBanner_: boolean; @@ -254,7 +255,7 @@ private updatePrivacyGuidePromoVisibility_() { if (!this.isPrivacyGuideAvailable || - this.pageVisibility.privacy === false || this.prefs === undefined || + this.pageVisibility_.privacy === false || this.prefs === undefined || this.getPref('privacy_guide.viewed').value || this.privacyGuideBrowserProxy_.getPromoImpressionCount() >= MAX_PRIVACY_GUIDE_PROMO_IMPRESSION || @@ -286,7 +287,7 @@ getSearchManager().search(query, basicPage), ]; - if (this.pageVisibility.advancedSettings !== false) { + if (this.pageVisibility_.advancedSettings !== false) { whenSearchDone.push(this.getIdleLoad_().then(function(advancedPage) { return getSearchManager().search(query, advancedPage); }));
diff --git a/chrome/browser/resources/settings/glic_page/glic_page.html b/chrome/browser/resources/settings/glic_page/glic_page.html index a9efb12..601a4ed9 100644 --- a/chrome/browser/resources/settings/glic_page/glic_page.html +++ b/chrome/browser/resources/settings/glic_page/glic_page.html
@@ -163,17 +163,17 @@ <settings-toggle-button id="geolocationToggle" pref="[[fakePref_]]" disabled label="$i18n{glicLocationToggle}" - sub-label="$i18n{glicLocationToggleSublabel}"> + sub-label="[[locationSubLabel_]]"> </settings-toggle-button> <settings-toggle-button id="microphoneToggle" pref="[[fakePref_]]" disabled label="$i18n{glicMicrophoneToggle}" - sub-label="$i18n{glicMicrophoneToggleSublabel}"> + sub-label="[[microphoneSubLabel_]]"> </settings-toggle-button> <settings-toggle-button id="tabAccessToggle" pref="[[fakePref_]]" disabled label="$i18n{glicTabAccessToggle}" - sub-label="$i18n{glicTabAccessToggleSublabel}"> + sub-label="[[tabAccessSubLabel_]]"> </settings-toggle-button> </template> @@ -182,22 +182,22 @@ <settings-toggle-button id="geolocationToggle" pref="{{prefs.glic.geolocation_enabled}}" label="$i18n{glicLocationToggle}" - sub-label="$i18n{glicLocationToggleSublabel}" - learn-more-url="$i18n{glicLocationToggleLearnMoreUrl}" + sub-label="[[locationSubLabel_]]" + learn-more-url="[[locationLearnMoreUrl_]]" on-learn-more-clicked="onLocationToggleLearnMoreClick_" on-settings-boolean-control-change="onGeolocationToggleChange_"> </settings-toggle-button> <settings-toggle-button id="microphoneToggle" pref="{{prefs.glic.microphone_enabled}}" label="$i18n{glicMicrophoneToggle}" - sub-label="$i18n{glicMicrophoneToggleSublabel}" + sub-label="[[microphoneSubLabel_]]" on-settings-boolean-control-change="onMicrophoneToggleChange_"> </settings-toggle-button> <settings-toggle-button id="tabAccessToggle" pref="{{prefs.glic.tab_context_enabled}}" label="$i18n{glicTabAccessToggle}" - sub-label="$i18n{glicTabAccessToggleSublabel}" - learn-more-url="$i18n{glicTabAccessToggleLearnMoreUrl}" + sub-label="[[tabAccessSubLabel_]]" + learn-more-url="[[tabAccessLearnMoreUrl_]]" on-learn-more-clicked="onTabAccessToggleLearnMoreClick_" on-settings-boolean-control-change="onTabAccessToggleChange_"> <div id="tabAccessToggleActions" slot="more-actions"> @@ -252,7 +252,7 @@ <div class="secondary">$i18n{glicTabAccessConsider1} <a id="shortcutTabAccessConsider1LearnMoreLabel" class="learn-more-label" - href="$i18n{glicTabAccessToggleLearnMoreUrl}" + href="[[tabAccessLearnMoreUrl_]]" on-click="onTabAccessToggleLearnMoreClick_" aria-label= "$i18n{glicTabAccessConsider1LearnMoreLabel}"
diff --git a/chrome/browser/resources/settings/glic_page/glic_page.ts b/chrome/browser/resources/settings/glic_page/glic_page.ts index 2b4f4f70..adf8775 100644 --- a/chrome/browser/resources/settings/glic_page/glic_page.ts +++ b/chrome/browser/resources/settings/glic_page/glic_page.ts
@@ -45,6 +45,7 @@ SETTINGS_POLICY = 'browser.gemini_settings', TAB_CONTEXT_ENABLED = 'glic.tab_context_enabled', TABSTRIP_BUTTON_ENABLED = 'glic.pinned_to_tabstrip', + USER_STATUS = 'glic.user_status', } // browser_element_identifiers constants @@ -52,6 +53,11 @@ const OS_WIDGET_KEYBOARD_SHORTCUT_ELEMENT_ID = 'kGlicOsWidgetKeyboardShortcutElementId'; +// Partial structure of the glic.user_status dictionary pref. +interface GlicUserStatusPref { + isEnterpriseAccountDataProtected?: boolean; +} + const SettingsGlicPageElementBase = HelpBubbleMixin(I18nMixin(WebUiListenerMixin(PrefsMixin(PolymerElement)))); @@ -104,6 +110,42 @@ return loadTimeData.getBoolean('glicClosedCaptionsFeatureEnabled'); }, }, + + glicUserStatusCheckFeatureEnabled_: { + type: Boolean, + value: () => + loadTimeData.getBoolean('glicUserStatusCheckFeatureEnabled'), + }, + + locationSubLabel_: { + type: String, + computed: `computeLocationSubLabel_(prefs.${ + SettingsGlicPageFeaturePrefName.USER_STATUS}.value)`, + }, + + locationLearnMoreUrl_: { + type: String, + computed: `computeLocationLearnMoreUrl_(prefs.${ + SettingsGlicPageFeaturePrefName.USER_STATUS}.value)`, + }, + + microphoneSubLabel_: { + type: String, + computed: `computeMicrophoneSubLabel_(prefs.${ + SettingsGlicPageFeaturePrefName.USER_STATUS}.value)`, + }, + + tabAccessSubLabel_: { + type: String, + computed: `computeTabAccessSubLabel_(prefs.${ + SettingsGlicPageFeaturePrefName.USER_STATUS}.value)`, + }, + + tabAccessLearnMoreUrl_: { + type: String, + computed: `computeTabAccessLearnMoreUrl_(prefs.${ + SettingsGlicPageFeaturePrefName.USER_STATUS}.value)`, + }, }; } @@ -126,6 +168,12 @@ MetricsBrowserProxyImpl.getInstance(); declare private tabAccessToggleExpanded_: boolean; declare private closedCaptionsFeatureEnabled_: boolean; + declare private glicUserStatusCheckFeatureEnabled_: boolean; + declare private locationSubLabel_: string; + declare private locationLearnMoreUrl_: string; + declare private microphoneSubLabel_: string; + declare private tabAccessSubLabel_: string; + declare private tabAccessLearnMoreUrl_: string; override async connectedCallback() { super.connectedCallback(); @@ -299,6 +347,46 @@ this.metricsBrowserProxy_.recordAction( 'Glic.Settings.TabstripButton.' + (enabled ? 'Enabled' : 'Disabled')); } + + private computeLocationSubLabel_(userStatus: GlicUserStatusPref|undefined): + string { + return this.glicUserStatusCheckFeatureEnabled_ && + userStatus?.isEnterpriseAccountDataProtected ? + this.i18n('glicLocationToggleSublabelDataProtected') : + this.i18n('glicLocationToggleSublabel'); + } + + private computeLocationLearnMoreUrl_( + userStatus: GlicUserStatusPref|undefined): string { + return this.glicUserStatusCheckFeatureEnabled_ && + userStatus?.isEnterpriseAccountDataProtected ? + '' : + this.i18n('glicLocationToggleLearnMoreUrl'); + } + + private computeMicrophoneSubLabel_(userStatus: GlicUserStatusPref|undefined): + string { + return this.glicUserStatusCheckFeatureEnabled_ && + userStatus?.isEnterpriseAccountDataProtected ? + this.i18n('glicMicrophoneToggleSublabelDataProtected') : + this.i18n('glicMicrophoneToggleSublabel'); + } + + private computeTabAccessSubLabel_(userStatus: GlicUserStatusPref|undefined): + string { + return this.glicUserStatusCheckFeatureEnabled_ && + userStatus?.isEnterpriseAccountDataProtected ? + this.i18n('glicTabAccessToggleSublabelDataProtected') : + this.i18n('glicTabAccessToggleSublabel'); + } + + private computeTabAccessLearnMoreUrl_( + userStatus: GlicUserStatusPref|undefined): string { + return this.glicUserStatusCheckFeatureEnabled_ && + userStatus?.isEnterpriseAccountDataProtected ? + this.i18n('glicTabAccessToggleLearnMoreUrlDataProtected') : + this.i18n('glicTabAccessToggleLearnMoreUrl'); + } } declare global {
diff --git a/chrome/browser/resources/settings/people_page/people_page.html b/chrome/browser/resources/settings/people_page/people_page.html index 5a30827..6a1aa09e 100644 --- a/chrome/browser/resources/settings/people_page/people_page.html +++ b/chrome/browser/resources/settings/people_page/people_page.html
@@ -166,7 +166,6 @@ learn-more-url="$i18n{syncAndGoogleServicesLearnMoreURL}"> <settings-sync-page sync-status="[[syncStatus]]" prefs="{{prefs}}" - page-visibility="[[pageVisibility.privacy]]" focus-config="[[focusConfig_]]"> </settings-sync-page> </settings-subpage>
diff --git a/chrome/browser/resources/settings/people_page/people_page.ts b/chrome/browser/resources/settings/people_page/people_page.ts index 22f5b17..7ed846f 100644 --- a/chrome/browser/resources/settings/people_page/people_page.ts +++ b/chrome/browser/resources/settings/people_page/people_page.ts
@@ -41,7 +41,6 @@ import {BaseMixin} from '../base_mixin.js'; import type {FocusConfig} from '../focus_config.js'; import {loadTimeData} from '../i18n_setup.js'; -import type {PageVisibility} from '../page_visibility.js'; import {routes} from '../route.js'; import {Router} from '../router.js'; @@ -131,11 +130,6 @@ syncStatus: Object, /** - * Dictionary defining page visibility. - */ - pageVisibility: Object, - - /** * Authentication token provided by settings-lock-screen. */ authToken_: { @@ -214,7 +208,6 @@ declare private signinAllowed_: boolean; declare private isDasherlessProfile_: boolean; declare syncStatus: SyncStatus|null; - declare pageVisibility: PageVisibility; declare private authToken_: string; declare private profileIconUrl_: string; declare private isProfileActionable_: boolean;
diff --git a/chrome/browser/resources/settings/people_page/sync_page.html b/chrome/browser/resources/settings/people_page/sync_page.html index 64e24bd5..371deb2 100644 --- a/chrome/browser/resources/settings/people_page/sync_page.html +++ b/chrome/browser/resources/settings/people_page/sync_page.html
@@ -218,7 +218,7 @@ </h2> </div> <settings-personalization-options class="list-frame" prefs="{{prefs}}" - page-visibility="[[pageVisibility]]" sync-status="[[syncStatus]]"> + sync-status="[[syncStatus]]"> </settings-personalization-options> <if expr="not chromeos_ash">
diff --git a/chrome/browser/resources/settings/people_page/sync_page.ts b/chrome/browser/resources/settings/people_page/sync_page.ts index 277c220..486349c 100644 --- a/chrome/browser/resources/settings/people_page/sync_page.ts +++ b/chrome/browser/resources/settings/people_page/sync_page.ts
@@ -42,7 +42,6 @@ import {loadTimeData} from '../i18n_setup.js'; import type {MetricsBrowserProxy} from '../metrics_browser_proxy.js'; import {MetricsBrowserProxyImpl} from '../metrics_browser_proxy.js'; -import type {PageVisibility} from '../page_visibility.js'; // <if expr="chromeos_ash"> import type {SettingsPersonalizationOptionsElement} from '../privacy_page/personalization_options.js'; // </if> @@ -110,14 +109,6 @@ }, /** - * Dictionary defining page visibility. - * TODO(dpapad): Restore the type information here - * (PrivacyPageVisibility), when this file is no longer shared with - * chrome://os-settings. - */ - pageVisibility: Object, - - /** * The current sync preferences, supplied by SyncBrowserProxy. */ syncPrefs: Object, @@ -229,7 +220,6 @@ declare prefs: {[key: string]: any}; declare focusConfig: FocusConfig; declare private pageStatus_: PageStatus; - declare pageVisibility: PageVisibility; declare syncPrefs?: SyncPrefs; declare syncStatus: SyncStatus; declare private dataEncrypted_: boolean;
diff --git a/chrome/browser/resources/settings/privacy_page/personalization_options.ts b/chrome/browser/resources/settings/privacy_page/personalization_options.ts index 5f18f4ac..3550dc3 100644 --- a/chrome/browser/resources/settings/privacy_page/personalization_options.ts +++ b/chrome/browser/resources/settings/privacy_page/personalization_options.ts
@@ -38,6 +38,7 @@ import type {SettingsToggleButtonElement} from '../controls/settings_toggle_button.js'; import {loadTimeData} from '../i18n_setup.js'; +import {pageVisibility} from '../page_visibility.js'; import type {PrivacyPageVisibility} from '../page_visibility.js'; import type {SettingsSignoutDialogElement} from '../people_page/signout_dialog.js'; import {RelaunchMixin, RestartType} from '../relaunch_mixin.js'; @@ -75,8 +76,6 @@ static get properties() { return { - pageVisibility: Object, - syncStatus: Object, // <if expr="_google_chrome and not chromeos_ash"> @@ -140,7 +139,6 @@ }; } - declare pageVisibility: PrivacyPageVisibility; declare syncStatus: SyncStatus; // <if expr="_google_chrome and not chromeos_ash"> @@ -257,18 +255,18 @@ // </if> private showSearchSuggestToggle_(): boolean { - if (this.pageVisibility === undefined) { + if (pageVisibility?.privacy === undefined) { // pageVisibility isn't defined in non-Guest profiles (crbug.com/1288911). return true; } - return this.pageVisibility.searchPrediction; + return (pageVisibility.privacy as PrivacyPageVisibility).searchPrediction; } + // <if expr="chromeos_ash"> private navigateTo_(url: string): void { window.location.href = url; } - // <if expr="chromeos_ash"> private onMetricsReportingLinkClick_() { // TODO(wesokuhara) Deep link directly to metrics toggle via settingId. this.navigateTo_(loadTimeData.getString('osSettingsPrivacyHubSubpageUrl'));
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.html b/chrome/browser/resources/settings/settings_main/settings_main.html index 329e955..7fca649 100644 --- a/chrome/browser/resources/settings/settings_main/settings_main.html +++ b/chrome/browser/resources/settings/settings_main/settings_main.html
@@ -37,7 +37,6 @@ <settings-basic-page class="cr-centered-card-container" prefs="{{prefs}}" - page-visibility="[[pageVisibility]]" on-subpage-expand="onShowingSubpage_" on-showing-main-page="onShowingMainPage_" in-search-mode="[[inSearchMode_]]">
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.ts b/chrome/browser/resources/settings/settings_main/settings_main.ts index 43fd55ea..15d9735 100644 --- a/chrome/browser/resources/settings/settings_main/settings_main.ts +++ b/chrome/browser/resources/settings/settings_main/settings_main.ts
@@ -23,7 +23,6 @@ import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {loadTimeData} from '../i18n_setup.js'; -import type {PageVisibility} from '../page_visibility.js'; import {routes} from '../route.js'; import {RouteObserverMixin, Router} from '../router.js'; @@ -93,11 +92,6 @@ value: false, notify: true, }, - - /** - * Dictionary defining page visibility. - */ - pageVisibility: Object, }; } @@ -107,7 +101,6 @@ declare private showNoResultsFound_: boolean; declare private showingSubpage_: boolean; declare toolbarSpinnerActive: boolean; - declare pageVisibility?: PageVisibility; /** * Updates the hidden state of the about and settings pages based on the
diff --git a/chrome/browser/resources/settings/settings_menu/settings_menu.html b/chrome/browser/resources/settings/settings_menu/settings_menu.html index 80c5ee1..acbddcd 100644 --- a/chrome/browser/resources/settings/settings_menu/settings_menu.html +++ b/chrome/browser/resources/settings/settings_menu/settings_menu.html
@@ -46,7 +46,7 @@ attr-for-selected="href" on-iron-activate="onSelectorActivate_" on-click="onLinkClick_" selected-attribute="selected"> <a role="menuitem" - id="people" href="/people" hidden="[[!pageVisibility.people]]" + id="people" href="/people" hidden="[[!pageVisibility_.people]]" class="cr-nav-menu-item"> <if expr="not _google_chrome"> <cr-icon icon="settings:person"></cr-icon> @@ -58,14 +58,14 @@ <cr-ripple></cr-ripple> </a> <a role="menuitem" id="autofill" href="/autofill" - hidden="[[!pageVisibility.autofill]]" + hidden="[[!pageVisibility_.autofill]]" class="cr-nav-menu-item"> <cr-icon icon="settings:assignment"></cr-icon> $i18n{autofillPageTitle} <cr-ripple></cr-ripple> </a> <a role="menuitem" href="/privacy" - hidden="[[!pageVisibility.privacy]]" + hidden="[[!pageVisibility_.privacy]]" class="cr-nav-menu-item"> <cr-icon icon="settings:security"></cr-icon> $i18n{privacyPageTitle} @@ -73,13 +73,13 @@ </a> <a role="menuitem" id="performance" href="/performance" class="cr-nav-menu-item" - hidden="[[!pageVisibility.performance]]"> + hidden="[[!pageVisibility_.performance]]"> <cr-icon icon="settings:navigation-performance"></cr-icon> $i18n{performancePageTitle} <cr-ripple></cr-ripple> </a> <a role="menuitem" href="/ai" - hidden="[[!showAiPageMenuItem_(showAiPage_, pageVisibility.ai)]]" + hidden="[[!showAiPageMenuItem_(showAiPage_, pageVisibility_.ai)]]" on-click="onAiPageClick_" class="cr-nav-menu-item"> <cr-icon icon="settings20:magic"></cr-icon> @@ -87,7 +87,7 @@ <cr-ripple></cr-ripple> </a> <a role="menuitem" id="appearance" href="/appearance" - hidden="[[!pageVisibility.appearance]]" + hidden="[[!pageVisibility_.appearance]]" class="cr-nav-menu-item"> <cr-icon icon="settings:palette"></cr-icon> $i18n{appearancePageTitle} @@ -101,7 +101,7 @@ <if expr="not is_chromeos"> <a role="menuitem" id="defaultBrowser" class="cr-nav-menu-item" href="/defaultBrowser" - hidden="[[!pageVisibility.defaultBrowser]]"> + hidden="[[!pageVisibility_.defaultBrowser]]"> <cr-icon icon="settings:web"></cr-icon> $i18n{defaultBrowser} <cr-ripple></cr-ripple> @@ -109,7 +109,7 @@ </if> <a role="menuitem" id="onStartup" href="/onStartup" class="cr-nav-menu-item" - hidden="[[!pageVisibility.onStartup]]"> + hidden="[[!pageVisibility_.onStartup]]"> <cr-icon icon="settings:power-settings"></cr-icon> $i18n{onStartup} <cr-ripple></cr-ripple> @@ -117,44 +117,44 @@ <div class="menu-separator"></div> <a role="menuitem" id="languages" href="/languages" class="cr-nav-menu-item" - hidden="[[!pageVisibility.languages]]"> + hidden="[[!pageVisibility_.languages]]"> <cr-icon icon="settings:navigation-language"></cr-icon> $i18n{languagesPageTitle} <cr-ripple></cr-ripple> </a> <a role="menuitem" id="downloads" href="/downloads" class="cr-nav-menu-item" - hidden="[[!pageVisibility.downloads]]"> + hidden="[[!pageVisibility_.downloads]]"> <cr-icon icon="settings:download"></cr-icon> $i18n{downloadsPageTitle} <cr-ripple></cr-ripple> </a> <a role="menuitem" id="accessibility" href="/accessibility" class="cr-nav-menu-item" - hidden="[[!pageVisibility.a11y]]"> + hidden="[[!pageVisibility_.a11y]]"> <cr-icon icon="settings:accessibility"></cr-icon> $i18n{a11yPageTitle} <cr-ripple></cr-ripple> </a> <if expr="not chromeos_ash"> <a role="menuitem" id="system" href="/system" class="cr-nav-menu-item" - hidden="[[!pageVisibility.system]]"> + hidden="[[!pageVisibility_.system]]"> <cr-icon icon="settings:system"></cr-icon> $i18n{systemPageTitle} <cr-ripple></cr-ripple> </a> </if> <a role="menuitem" id="reset" href="/reset" - hidden="[[!pageVisibility.reset]]" class="cr-nav-menu-item"> + hidden="[[!pageVisibility_.reset]]" class="cr-nav-menu-item"> <cr-icon icon="settings:restore"></cr-icon> $i18n{resetPageTitle} <cr-ripple></cr-ripple> </a> - <div hidden="[[!pageVisibility.advancedSettings]]" + <div hidden="[[!pageVisibility_.advancedSettings]]" class="menu-separator"></div> <a role="menuitem" id="extensionsLink" class="cr-nav-menu-item" href="chrome://extensions" target="_blank" - hidden="[[!pageVisibility.extensions]]" + hidden="[[!pageVisibility_.extensions]]" on-click="onExtensionsLinkClick_" title="$i18n{extensionsLinkTooltip}"> <cr-icon icon="settings:extension"></cr-icon>
diff --git a/chrome/browser/resources/settings/settings_menu/settings_menu.ts b/chrome/browser/resources/settings/settings_menu/settings_menu.ts index 843c8e4..53a0808c 100644 --- a/chrome/browser/resources/settings/settings_menu/settings_menu.ts +++ b/chrome/browser/resources/settings/settings_menu/settings_menu.ts
@@ -28,6 +28,7 @@ import {loadTimeData} from '../i18n_setup.js'; import type {MetricsBrowserProxy} from '../metrics_browser_proxy.js'; import {MetricsBrowserProxyImpl} from '../metrics_browser_proxy.js'; +import {pageVisibility} from '../page_visibility.js'; import type {PageVisibility} from '../page_visibility.js'; import type {Route} from '../router.js'; import {RouteObserverMixin, Router} from '../router.js'; @@ -58,7 +59,10 @@ /** * Dictionary defining page visibility. */ - pageVisibility: Object, + pageVisibility_: { + type: Object, + value: () => pageVisibility, + }, showAiPage_: { type: Boolean, @@ -67,14 +71,14 @@ }; } - declare pageVisibility?: PageVisibility; + declare private pageVisibility_?: PageVisibility; declare private showAiPage_: boolean; private metricsBrowserProxy_: MetricsBrowserProxy = MetricsBrowserProxyImpl.getInstance(); private showAiPageMenuItem_(): boolean { return this.showAiPage_ && - (!this.pageVisibility || this.pageVisibility.ai !== false); + (!this.pageVisibility_ || this.pageVisibility_.ai !== false); } override currentRouteChanged(newRoute: Route) {
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.html b/chrome/browser/resources/settings/settings_ui/settings_ui.html index 554a8d660..2d7c55d 100644 --- a/chrome/browser/resources/settings/settings_ui/settings_ui.html +++ b/chrome/browser/resources/settings/settings_ui/settings_ui.html
@@ -101,23 +101,18 @@ align="$i18n{textdirection}"> <div slot="body"> <template is="dom-if" id="drawerTemplate"> - <settings-menu id="drawerMenu" - page-visibility="[[pageVisibility_]]" - on-iron-activate="onIronActivate_"> + <settings-menu id="drawerMenu" on-iron-activate="onIronActivate_"> </settings-menu> </template> </div> </cr-drawer> <div id="container" class="no-outline"> <div id="left" hidden$="[[narrow_]]"> - <settings-menu id="leftMenu" - page-visibility="[[pageVisibility_]]" - on-iron-activate="onIronActivate_"> + <settings-menu id="leftMenu" on-iron-activate="onIronActivate_"> </settings-menu> </div> <settings-main id="main" prefs="{{prefs}}" - toolbar-spinner-active="{{toolbarSpinnerActive_}}" - page-visibility="[[pageVisibility_]]"> + toolbar-spinner-active="{{toolbarSpinnerActive_}}"> </settings-main> <!-- An additional child of the flex #container to take up space, aligned with the right-hand child of the flex toolbar. -->
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.ts b/chrome/browser/resources/settings/settings_ui/settings_ui.ts index 1256cca7..993e5f4c 100644 --- a/chrome/browser/resources/settings/settings_ui/settings_ui.ts +++ b/chrome/browser/resources/settings/settings_ui/settings_ui.ts
@@ -33,8 +33,6 @@ import {resetGlobalScrollTargetForTesting, setGlobalScrollTarget} from '../global_scroll_target_mixin.js'; import {loadTimeData} from '../i18n_setup.js'; -import type {PageVisibility} from '../page_visibility.js'; -import {pageVisibility} from '../page_visibility.js'; import {routes} from '../route.js'; import type {Route} from '../router.js'; import {RouteObserverMixin, Router} from '../router.js'; @@ -90,8 +88,6 @@ observer: 'onNarrowChanged_', }, - pageVisibility_: {type: Object, value: pageVisibility}, - lastSearchQuery_: { type: String, value: '', @@ -102,7 +98,6 @@ declare prefs: {[key: string]: any}; declare private toolbarSpinnerActive_: boolean; declare private narrow_: boolean; - declare private pageVisibility_: PageVisibility; declare private lastSearchQuery_: string; constructor() {
diff --git a/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc b/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc index 9a5cae6..2ca0f99 100644 --- a/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc +++ b/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc
@@ -6,6 +6,7 @@ #include <algorithm> +#include "base/barrier_callback.h" #include "base/cancelable_callback.h" #include "base/containers/span.h" #include "base/functional/bind.h" @@ -359,6 +360,7 @@ } #if !BUILDFLAG(IS_ANDROID) + // TODO(chlily): Factor this out into delegate's modifications. if (is_enhanced_protection_ && token_fetcher_) { token_fetcher_->Start(base::BindOnce( &CheckClientDownloadRequestBase::OnGotAccessToken, GetWeakPtr())); @@ -366,6 +368,36 @@ } #endif + StartModificationsFromDelegate(); +} + +void CheckClientDownloadRequestBase::StartModificationsFromDelegate() { + std::vector<PendingClientDownloadRequestModification> pending_modifications = + service_->delegate()->ProduceClientDownloadRequestModifications(item()); + + const auto collect_modifications_repeating = + base::BarrierCallback<ClientDownloadRequestModification>( + pending_modifications.size(), + base::BindOnce( + &CheckClientDownloadRequestBase::ApplyModificationsAndSendRequest, + GetWeakPtr())); + + // Kick off all the modifications. + for (auto& pending_modification : pending_modifications) { + // Make a separate copy of the BarrierCallback for each pending + // modification. They must each call their own copy of + // `collect_modifications_repeating` exactly once. + CollectModificationCallback collect_modification = + collect_modifications_repeating; + std::move(pending_modification).Run(std::move(collect_modification)); + } +} + +void CheckClientDownloadRequestBase::ApplyModificationsAndSendRequest( + std::vector<ClientDownloadRequestModification> modifications) { + for (auto& modification : modifications) { + std::move(modification).Run(client_download_request_.get()); + } SendRequest(); } @@ -386,7 +418,8 @@ void CheckClientDownloadRequestBase::OnGotAccessToken( const std::string& access_token) { access_token_ = access_token; - SendRequest(); + + StartModificationsFromDelegate(); } #endif @@ -402,9 +435,6 @@ skipped_certificate_allowlist_); CHECK(service_); - - service_->delegate()->PreSerializeRequest(item(), *client_download_request_); - if (!client_download_request_->SerializeToString( &client_download_request_data_)) { FinishRequest(DownloadCheckResult::UNKNOWN, REASON_INVALID_REQUEST_PROTO);
diff --git a/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.h b/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.h index 2323c2da..10f6711 100644 --- a/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.h +++ b/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.h
@@ -88,6 +88,20 @@ void OnRequestBuilt(DownloadRequestMaker::RequestCreationDetails details, std::unique_ptr<ClientDownloadRequest> request_proto); + // Give the DownloadProtectionDelegate a chance to modify the request proto + // in various ways before serializing and sending it. This is a two-phase + // process because the individual modifications may be asynchronous. + // First, `StartModificationsFromDelegate()` solicits a number of pending + // modifications from the delegate, in the form of callbacks, which it + // kicks off to evaluate the modifications (potentially simultaneously and + // asynchronously). Then, `ApplyModificationsAndSendRequest` is run when the + // modifications have all been computed, to apply the modifications and + // continue with the request flow. There are no ordering guarantees on the + // modifications that ultimately get run. + void StartModificationsFromDelegate(); + void ApplyModificationsAndSendRequest( + std::vector<ClientDownloadRequestModification> modifications); + void StartTimeout(); void SendRequest(); void OnURLLoaderComplete(std::unique_ptr<std::string> response_body);
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_delegate.cc b/chrome/browser/safe_browsing/download_protection/download_protection_delegate.cc index ef0d5ca..2a648d8 100644 --- a/chrome/browser/safe_browsing/download_protection/download_protection_delegate.cc +++ b/chrome/browser/safe_browsing/download_protection/download_protection_delegate.cc
@@ -22,4 +22,10 @@ #endif } +std::vector<PendingClientDownloadRequestModification> +DownloadProtectionDelegate::ProduceClientDownloadRequestModifications( + const download::DownloadItem* item) { + return std::vector<PendingClientDownloadRequestModification>(); +} + } // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_delegate.h b/chrome/browser/safe_browsing/download_protection/download_protection_delegate.h index 076f080..1dfff2d4 100644 --- a/chrome/browser/safe_browsing/download_protection/download_protection_delegate.h +++ b/chrome/browser/safe_browsing/download_protection/download_protection_delegate.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_SAFE_BROWSING_DOWNLOAD_PROTECTION_DOWNLOAD_PROTECTION_DELEGATE_H_ #include <memory> +#include <vector> #include "chrome/browser/safe_browsing/download_protection/download_protection_util.h" #include "net/traffic_annotation/network_traffic_annotation.h" @@ -72,12 +73,17 @@ download::DownloadItem& item, const base::FilePath& target_path) const = 0; - // Called immediately prior to serializing the ClientDownloadRequest into the - // string to send in the POST request body, which is followed by sending out - // the network request. Allows the delegate to make final modifications to - // the request. `item` is the download this pertains to, which may be null. - virtual void PreSerializeRequest(const download::DownloadItem* item, - ClientDownloadRequest& request_proto) {} + // Called after the ClientDownloadRequest has been constructed, prior to + // serializing the ClientDownloadRequest into a string to send in the POST + // request body of the network request. Allows the delegate to request final + // modifications to apply to the request, in the form of a vector of callbacks + // to invoke, each of which will yield a modification to be made to + // ClientDownloadRequest. + // + // `item` is the download this pertains to, which may be null, e.g. if this + // request is not for a download. + virtual std::vector<PendingClientDownloadRequestModification> + ProduceClientDownloadRequestModifications(const download::DownloadItem* item); // Called immediately prior to consuming the ResourceRequest used to send out // a download ping. Allows the delegate to make final modifications to the
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_delegate_android.cc b/chrome/browser/safe_browsing/download_protection/download_protection_delegate_android.cc index 3dec239d..9a6d172 100644 --- a/chrome/browser/safe_browsing/download_protection/download_protection_delegate_android.cc +++ b/chrome/browser/safe_browsing/download_protection/download_protection_delegate_android.cc
@@ -8,6 +8,7 @@ #include "base/feature_list.h" #include "base/files/file_path.h" +#include "base/functional/bind.h" #include "base/metrics/histogram_functions.h" #include "base/notreached.h" #include "base/rand_util.h" @@ -106,6 +107,36 @@ "SBClientDownload.Android.GetReferringAppInfo.Result", result); } +void PopulateReferringAppInfoInProto(internal::ReferringAppInfo info, + ClientDownloadRequest* request_proto) { + *request_proto->mutable_referring_app_info() = GetReferringAppInfoProto(info); +} + +void MaybePopulateReferringAppInfo(const download::DownloadItem* item, + CollectModificationCallback callback) { + CHECK(item); + // Note: The web_contents will be null if the original download page has + // been navigated away from. + content::WebContents* web_contents = + content::DownloadItemUtils::GetWebContents(item); + if (!web_contents) { + LogGetReferringAppInfoResult( + internal::GetReferringAppInfoResult::kNotAttempted); + std::move(callback).Run(NoModificationToRequestProto()); + return; + } + internal::ReferringAppInfo info = + GetReferringAppInfo(web_contents, /*get_webapk_info=*/true); + LogGetReferringAppInfoResult(internal::ReferringAppInfoToResult(info)); + if (!info.has_referring_app() && !info.has_referring_webapk()) { + std::move(callback).Run(NoModificationToRequestProto()); + return; + } + + std::move(callback).Run( + base::BindOnce(&PopulateReferringAppInfoInProto, std::move(info))); +} + } // namespace DownloadProtectionDelegateAndroid::DownloadProtectionDelegateAndroid() @@ -172,30 +203,16 @@ return may_check_download_result; } -void DownloadProtectionDelegateAndroid::PreSerializeRequest( - const download::DownloadItem* item, - safe_browsing::ClientDownloadRequest& request_proto) { - if (!item) { - return; - } +std::vector<PendingClientDownloadRequestModification> +DownloadProtectionDelegateAndroid::ProduceClientDownloadRequestModifications( + const download::DownloadItem* item) { + std::vector<PendingClientDownloadRequestModification> modifications; - // Populate the ReferringAppInfo in the ClientDownloadRequest. - // Note: The web_contents will be null if the original download page has - // been navigated away from. - content::WebContents* web_contents = - content::DownloadItemUtils::GetWebContents(item); - if (!web_contents) { - LogGetReferringAppInfoResult( - internal::GetReferringAppInfoResult::kNotAttempted); - return; + if (item) { + modifications.emplace_back( + base::BindOnce(&MaybePopulateReferringAppInfo, item)); } - internal::ReferringAppInfo info = - GetReferringAppInfo(web_contents, /*get_webapk_info=*/true); - LogGetReferringAppInfoResult(internal::ReferringAppInfoToResult(info)); - if (!info.has_referring_app() && !info.has_referring_webapk()) { - return; - } - *request_proto.mutable_referring_app_info() = GetReferringAppInfoProto(info); + return modifications; } void DownloadProtectionDelegateAndroid::FinalizeResourceRequest(
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_delegate_android.h b/chrome/browser/safe_browsing/download_protection/download_protection_delegate_android.h index 00fed7e..72dc92c4 100644 --- a/chrome/browser/safe_browsing/download_protection/download_protection_delegate_android.h +++ b/chrome/browser/safe_browsing/download_protection/download_protection_delegate_android.h
@@ -45,8 +45,9 @@ MayCheckDownloadResult IsSupportedDownload( download::DownloadItem& item, const base::FilePath& target_path) const override; - void PreSerializeRequest(const download::DownloadItem* item, - ClientDownloadRequest& request_proto) override; + std::vector<PendingClientDownloadRequestModification> + ProduceClientDownloadRequestModifications( + const download::DownloadItem* item) override; void FinalizeResourceRequest( network::ResourceRequest& resource_request) override; const GURL& GetDownloadRequestUrl() const override;
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_util.cc b/chrome/browser/safe_browsing/download_protection/download_protection_util.cc index 0dcfed1..0e6bfa6 100644 --- a/chrome/browser/safe_browsing/download_protection/download_protection_util.cc +++ b/chrome/browser/safe_browsing/download_protection/download_protection_util.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/safe_browsing/download_protection/download_protection_util.h" +#include "base/functional/callback_helpers.h" #include "base/hash/sha1.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" @@ -168,6 +169,10 @@ } // namespace +ClientDownloadRequestModification NoModificationToRequestProto() { + return base::DoNothing(); +} + void GetCertificateAllowlistStrings( const net::X509Certificate& certificate, const net::X509Certificate& issuer,
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_util.h b/chrome/browser/safe_browsing/download_protection/download_protection_util.h index e238b3b2..4dd6843 100644 --- a/chrome/browser/safe_browsing/download_protection/download_protection_util.h +++ b/chrome/browser/safe_browsing/download_protection/download_protection_util.h
@@ -164,6 +164,28 @@ using PPAPIDownloadRequestCallback = PPAPIDownloadRequestCallbackList::CallbackType; +// Types used for the BarrierCallback mechanism in +// CheckClientDownloadRequestBase::StartModificationsFromDelegate(): + +// Callback that, when invoked, makes a modification to a ClientDownloadRequest. +using ClientDownloadRequestModification = + base::OnceCallback<void(ClientDownloadRequest*)>; +// Type of the helper callback that should be called exactly once for each +// ClientDownloadRequestModification that should be done. Calling the +// CollectModificationCallback collects a modification, i.e. registers the +// modification to be executed on the ClientDownloadRequest after all such +// modifications have been collected. +using CollectModificationCallback = + base::OnceCallback<void(ClientDownloadRequestModification)>; +// Callback that, when run, generates an appropriate +// ClientDownloadRequestModification that should be executed, and invokes +// the passed-in CollectModificationCallback with the desired modification. +using PendingClientDownloadRequestModification = + base::OnceCallback<void(CollectModificationCallback)>; + +// Returns a ClientDownloadRequestModification that is a no-op. +ClientDownloadRequestModification NoModificationToRequestProto(); + // Given a certificate and its immediate issuer certificate, generates the // list of strings that need to be checked against the download allowlist to // determine whether the certificate is allowlisted.
diff --git a/chrome/browser/sync/android/java/src/org/chromium/chrome/browser/sync/ui/BatchUploadDialogCoordinator.java b/chrome/browser/sync/android/java/src/org/chromium/chrome/browser/sync/ui/BatchUploadDialogCoordinator.java index d903bee..d3ae5a0 100644 --- a/chrome/browser/sync/android/java/src/org/chromium/chrome/browser/sync/ui/BatchUploadDialogCoordinator.java +++ b/chrome/browser/sync/android/java/src/org/chromium/chrome/browser/sync/ui/BatchUploadDialogCoordinator.java
@@ -20,6 +20,7 @@ import org.chromium.build.annotations.Nullable; import org.chromium.chrome.browser.sync.R; import org.chromium.components.browser_ui.widget.MaterialSwitchWithTitleAndSummary; +import org.chromium.components.signin.base.CoreAccountInfo; import org.chromium.components.sync.DataType; import org.chromium.components.sync.LocalDataDescription; import org.chromium.ui.modaldialog.DialogDismissalCause; @@ -58,10 +59,11 @@ Context context, HashMap<Integer, LocalDataDescription> localDataDescriptionsMap, ModalDialogManager dialogManager, + CoreAccountInfo accountInfo, Listener listener) { ThreadUtils.assertOnUiThread(); new BatchUploadDialogCoordinator( - context, localDataDescriptionsMap, dialogManager, listener); + context, localDataDescriptionsMap, dialogManager, accountInfo, listener); } @VisibleForTesting @@ -70,6 +72,7 @@ Context context, HashMap<Integer, LocalDataDescription> localDataDescriptionsMap, ModalDialogManager dialogManager, + CoreAccountInfo accountInfo, Listener listener) { mContext = context; mDialogManager = dialogManager; @@ -81,6 +84,13 @@ .with( ModalDialogProperties.TITLE, mContext.getString(R.string.batch_upload_dialog_title)) + // TODO(crbug.com/354922852): Handle accounts with non-displayable email + // address. + .with( + ModalDialogProperties.MESSAGE_PARAGRAPH_1, + mContext.getString( + R.string.batch_upload_dialog_description, + accountInfo.getEmail())) .with( ModalDialogProperties.POSITIVE_BUTTON_TEXT, mContext.getString(R.string.batch_upload_dialog_save_button))
diff --git a/chrome/browser/sync/android/java/src/org/chromium/chrome/browser/sync/ui/batch_upload_card/BatchUploadCardMediator.java b/chrome/browser/sync/android/java/src/org/chromium/chrome/browser/sync/ui/batch_upload_card/BatchUploadCardMediator.java index 317d64ba..f95694e6 100644 --- a/chrome/browser/sync/android/java/src/org/chromium/chrome/browser/sync/ui/batch_upload_card/BatchUploadCardMediator.java +++ b/chrome/browser/sync/android/java/src/org/chromium/chrome/browser/sync/ui/batch_upload_card/BatchUploadCardMediator.java
@@ -171,6 +171,7 @@ CoreAccountInfo coreAccountInfo = identityManager.getPrimaryAccountInfo(ConsentLevel.SIGNIN); assumeNonNull(coreAccountInfo); + // TODO(crbug.com/354922852): Handle accounts with non-displayable email address. String snackbarMessage = mContext.getResources() .getQuantityString( @@ -235,7 +236,6 @@ } private void setupBatchUploadCardPropertyModel() { - // TODO(crbug.com/354922852): Handle accounts with non-displayable email address. IdentityManager identityManager = IdentityServicesProvider.get().getIdentityManager(mProfile); assumeNonNull(identityManager); @@ -251,7 +251,7 @@ BatchUploadCardProperties.ON_CLICK_LISTENER, v -> { BatchUploadDialogCoordinator.show( - mContext, mLocalDataDescriptionsMap, mDialogManager, this); + mContext, mLocalDataDescriptionsMap, mDialogManager, accountInfo, this); }); int entryPointDataType = @@ -277,8 +277,7 @@ ? R.plurals.batch_upload_card_description_bookmark : R.plurals.batch_upload_card_description_password, localDataTypeItemsCount, - localDataTypeItemsCount, - accountInfo.getEmail())); + localDataTypeItemsCount)); } else if (localDataTypeItemsCount == 0) { mModel.set( BatchUploadCardProperties.DESCRIPTION_TEXT, @@ -286,8 +285,7 @@ .getQuantityString( R.plurals.batch_upload_card_description_other, localItemsCountExcludingEntryPointDataType, - localItemsCountExcludingEntryPointDataType, - accountInfo.getEmail())); + localItemsCountExcludingEntryPointDataType)); } else { mModel.set( BatchUploadCardProperties.DESCRIPTION_TEXT, @@ -299,8 +297,7 @@ : R.plurals .batch_upload_card_description_password_and_other, localDataTypeItemsCount, - localDataTypeItemsCount, - accountInfo.getEmail())); + localDataTypeItemsCount)); } } }
diff --git a/chrome/browser/sync/test/integration/saved_tab_groups_helper.cc b/chrome/browser/sync/test/integration/saved_tab_groups_helper.cc index a0f8411..7b064f7 100644 --- a/chrome/browser/sync/test/integration/saved_tab_groups_helper.cc +++ b/chrome/browser/sync/test/integration/saved_tab_groups_helper.cc
@@ -139,6 +139,52 @@ CheckExitCondition(); } +// ========================================== +// --- SavedTabGroupCountMatchesChecker --- +// ========================================== +SavedTabGroupCountMatchesChecker::SavedTabGroupCountMatchesChecker( + TabGroupSyncService* service, + size_t expected_tab_group_count, + bool count_shared_only) + : service_(service), + expected_tab_group_count_(expected_tab_group_count), + count_shared_only_(count_shared_only) { + CHECK(service_); + service_->AddObserver(this); +} + +SavedTabGroupCountMatchesChecker::~SavedTabGroupCountMatchesChecker() { + service_->RemoveObserver(this); +} + +bool SavedTabGroupCountMatchesChecker::IsExitConditionSatisfied( + std::ostream* os) { + size_t tab_group_count = 0; + for (const SavedTabGroup& group : service_->GetAllGroups()) { + if (count_shared_only_ && !group.collaboration_id()) { + continue; + } + tab_group_count++; + } + + *os << "Waiting for tab group count: expected = " << expected_tab_group_count_ + << ", actual = " << tab_group_count + << ", count_shared_only = " << count_shared_only_; + return expected_tab_group_count_ == tab_group_count; +} + +void SavedTabGroupCountMatchesChecker::OnTabGroupAdded( + const SavedTabGroup& group, + TriggerSource source) { + CheckExitCondition(); +} + +void SavedTabGroupCountMatchesChecker::OnTabGroupRemoved( + const base::Uuid& sync_id, + TriggerSource source) { + CheckExitCondition(); +} + // =================================== // --- SavedTabGroupMatchesChecker --- // ===================================
diff --git a/chrome/browser/sync/test/integration/saved_tab_groups_helper.h b/chrome/browser/sync/test/integration/saved_tab_groups_helper.h index b19247e..c211ae4 100644 --- a/chrome/browser/sync/test/integration/saved_tab_groups_helper.h +++ b/chrome/browser/sync/test/integration/saved_tab_groups_helper.h
@@ -95,6 +95,36 @@ raw_ptr<TabGroupSyncService> const service_; }; +// Checks that the number of expected saved tab groups matches with the service. +class SavedTabGroupCountMatchesChecker : public StatusChangeChecker, + public TabGroupSyncService::Observer { + public: + // The caller must ensure that `service` is not null and will outlive this + // object. + SavedTabGroupCountMatchesChecker(TabGroupSyncService* service, + size_t expected_tab_group_count, + bool count_shared_only); + SavedTabGroupCountMatchesChecker(const SavedTabGroupCountMatchesChecker&) = + delete; + SavedTabGroupCountMatchesChecker& operator=( + const SavedTabGroupCountMatchesChecker&) = delete; + ~SavedTabGroupCountMatchesChecker() override; + + // StatusChangeChecker implementation. + bool IsExitConditionSatisfied(std::ostream* os) override; + + // TabGroupSyncService::Observer. + void OnTabGroupAdded(const SavedTabGroup& group, + TriggerSource source) override; + void OnTabGroupRemoved(const base::Uuid& sync_id, + TriggerSource source) override; + + private: + raw_ptr<TabGroupSyncService> const service_; + const size_t expected_tab_group_count_; + const bool count_shared_only_; +}; + // Checks that a matching group exists in the service. class SavedTabGroupMatchesChecker : public StatusChangeChecker, public TabGroupSyncService::Observer {
diff --git a/chrome/browser/sync/test/integration/single_client_shared_tab_group_data_sync_test.cc b/chrome/browser/sync/test/integration/single_client_shared_tab_group_data_sync_test.cc index 0499cb0..7ec9121 100644 --- a/chrome/browser/sync/test/integration/single_client_shared_tab_group_data_sync_test.cc +++ b/chrome/browser/sync/test/integration/single_client_shared_tab_group_data_sync_test.cc
@@ -25,6 +25,7 @@ #include "components/saved_tab_groups/public/tab_group_sync_service.h" #include "components/saved_tab_groups/public/types.h" #include "components/saved_tab_groups/public/utils.h" +#include "components/saved_tab_groups/public/versioning_message_controller.h" #include "components/saved_tab_groups/test_support/saved_tab_group_test_utils.h" #include "components/signin/public/identity_manager/identity_test_utils.h" #include "components/sync/base/client_tag_hash.h" @@ -170,15 +171,14 @@ class SingleClientSharedTabGroupDataSyncTest : public SyncTest { public: - SingleClientSharedTabGroupDataSyncTest() : SyncTest(SINGLE_CLIENT) { + SingleClientSharedTabGroupDataSyncTest() : SyncTest(SINGLE_CLIENT) {} + ~SingleClientSharedTabGroupDataSyncTest() override = default; + + void SetUp() override { feature_overrides_.InitWithFeatures( {data_sharing::features::kDataSharingFeature, tab_groups::kTabGroupSyncServiceDesktopMigration}, {}); - } - ~SingleClientSharedTabGroupDataSyncTest() override = default; - - void SetUp() override { #if BUILDFLAG(IS_ANDROID) if (base::android::BuildInfo::GetInstance()->is_automotive()) { // TODO(crbug.com/399444939): Re-enable once automotive is supported. @@ -306,7 +306,7 @@ SyncTest::SetUpOnMainThread(); } - private: + protected: base::test::ScopedFeatureList feature_overrides_; }; @@ -821,6 +821,216 @@ UnorderedElementsAre(HasTabMetadata("tab 1", "http://google.com/1"), HasTabMetadata("tab 2", "http://google.com/2"))); } + +class SingleClientSharedTabGroupVersioningSyncTest + : public SingleClientSharedTabGroupDataSyncTest { + public: + SingleClientSharedTabGroupVersioningSyncTest() = default; + ~SingleClientSharedTabGroupVersioningSyncTest() override = default; + + void SetUp() override { + SetupFeatures(); + SyncTest::SetUp(); + } + + void SetupFeatures() { + // The test is consists of 4 sessions. + // Session 1: Version up-to-date. + // Session 2: Version out of date. + // Session 3: Version out of date. + // Session 4: Version updated. + // Setting the update chrome feature accordingly. + bool version_out_of_date = + IsSpecificTest( + "PRE_PRE_" + "ShouldShowVersioningMessagesAfterRestart") || + IsSpecificTest( + "PRE_" + "ShouldShowVersioningMessagesAfterRestart"); + if (version_out_of_date) { + feature_overrides_.InitWithFeatures( + {data_sharing::features::kDataSharingFeature, + tab_groups::kTabGroupSyncServiceDesktopMigration, + data_sharing::features::kDataSharingEnableUpdateChromeUI}, + {data_sharing::features::kSharedDataTypesKillSwitch}); + } else { + feature_overrides_.InitWithFeatures( + {data_sharing::features::kDataSharingFeature, + tab_groups::kTabGroupSyncServiceDesktopMigration, + data_sharing::features::kSharedDataTypesKillSwitch}, + {data_sharing::features::kDataSharingEnableUpdateChromeUI}); + } + } + + bool IsSpecificTest(const std::string& target_test_name) { + std::string current_test_name = + ::testing::UnitTest::GetInstance()->current_test_info()->name(); + return current_test_name == target_test_name; + } + + bool ExpectMessageUiShouldBeShown( + VersioningMessageController* versioning_message_controller, + VersioningMessageController::MessageType message_type) { + base::RunLoop run_loop; + bool actual_value = false; + versioning_message_controller->ShouldShowMessageUiAsync( + message_type, base::BindOnce( + [](base::RunLoop* run_loop, bool* actual_value_ptr, + bool actual_value_from_callback) { + *actual_value_ptr = actual_value_from_callback; + run_loop->Quit(); + }, + &run_loop, &actual_value)); + run_loop.Run(); + return actual_value; + } +}; + +// Versioning test with version up-to-date. +IN_PROC_BROWSER_TEST_F(SingleClientSharedTabGroupVersioningSyncTest, + PRE_PRE_PRE_ShouldShowVersioningMessagesAfterRestart) { + const base::Uuid group_guid = base::Uuid::GenerateRandomV4(); + const syncer::CollaborationId kCollaborationId("collaboration"); + + // SetupClients() must be called to get access to IdentityManager before + // injecting entities to the fake server. + ASSERT_TRUE(SetupClients()); + + AddSpecificsToFakeServer( + MakeSharedTabGroupSpecifics( + group_guid, + /*originating_saved_group_guid=*/base::Uuid::GenerateRandomV4(), + "title", sync_pb::SharedTabGroup_Color_CYAN), + kCollaborationId); + AddSpecificsToFakeServer( + MakeSharedTabGroupTabSpecifics(base::Uuid::GenerateRandomV4(), group_guid, + "tab 1", GURL("http://google.com/1")), + kCollaborationId); + AddSpecificsToFakeServer( + MakeSharedTabGroupTabSpecifics(base::Uuid::GenerateRandomV4(), group_guid, + "tab 2", GURL("http://google.com/2")), + kCollaborationId); + + ASSERT_TRUE(SetupSync()); + RegisterCollaboration(kCollaborationId); + + ASSERT_THAT(GetAllTabGroups(), SizeIs(1)); + + // Verify that the no versioning messages are available. + VersioningMessageController* versioning_message_controller = + GetTabGroupSyncService()->GetVersioningMessageController(); + EXPECT_FALSE( + ExpectMessageUiShouldBeShown(versioning_message_controller, + VersioningMessageController::MessageType:: + VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE)); + EXPECT_FALSE(ExpectMessageUiShouldBeShown( + versioning_message_controller, + VersioningMessageController::MessageType::VERSION_UPDATED_MESSAGE)); +} + +// Versioning test with version out-of-date after restart. +IN_PROC_BROWSER_TEST_F(SingleClientSharedTabGroupVersioningSyncTest, + PRE_PRE_ShouldShowVersioningMessagesAfterRestart) { + // Restart chrome with chrome version out-of-date. + const syncer::CollaborationId kCollaborationId("collaboration"); + ASSERT_TRUE(SetupClients()); + GetFakeServer()->AddCollaboration(kCollaborationId); + RegisterCollaboration(kCollaborationId); + ASSERT_TRUE(GetClient(0)->AwaitSyncTransportActive()); + + ASSERT_TRUE( + SavedTabGroupCountMatchesChecker(GetTabGroupSyncService(), 0, true) + .Wait()); + ASSERT_THAT(GetAllTabGroups(), SizeIs(0)); + + // Verify that the appropriate versioning messages are available. + VersioningMessageController* versioning_message_controller = + GetTabGroupSyncService()->GetVersioningMessageController(); + EXPECT_TRUE( + ExpectMessageUiShouldBeShown(versioning_message_controller, + VersioningMessageController::MessageType:: + VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE)); + EXPECT_FALSE(ExpectMessageUiShouldBeShown( + versioning_message_controller, + VersioningMessageController::MessageType::VERSION_UPDATED_MESSAGE)); + + // Mimic persistent message shown in the UI. + versioning_message_controller->OnMessageUiShown( + VersioningMessageController::MessageType:: + VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE); +} + +// Versioning test: Restart again with version out-of-date. +IN_PROC_BROWSER_TEST_F(SingleClientSharedTabGroupVersioningSyncTest, + PRE_ShouldShowVersioningMessagesAfterRestart) { + // Restart chrome with chrome version out-of-date. + const syncer::CollaborationId kCollaborationId("collaboration"); + ASSERT_TRUE(SetupClients()); + GetFakeServer()->AddCollaboration(kCollaborationId); + RegisterCollaboration(kCollaborationId); + ASSERT_TRUE(GetClient(0)->AwaitSyncTransportActive()); + + ASSERT_TRUE( + SavedTabGroupCountMatchesChecker(GetTabGroupSyncService(), 0, true) + .Wait()); + ASSERT_THAT(GetAllTabGroups(), SizeIs(0)); + + // Verify that the appropriate versioning messages are available. + VersioningMessageController* versioning_message_controller = + GetTabGroupSyncService()->GetVersioningMessageController(); + EXPECT_TRUE( + ExpectMessageUiShouldBeShown(versioning_message_controller, + VersioningMessageController::MessageType:: + VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE)); + EXPECT_FALSE(ExpectMessageUiShouldBeShown( + versioning_message_controller, + VersioningMessageController::MessageType::VERSION_UPDATED_MESSAGE)); + + // Mimic persistent message shown in the UI. + versioning_message_controller->OnMessageUiShown( + VersioningMessageController::MessageType:: + VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE); +} + +// Versioning test with version updated just now. +IN_PROC_BROWSER_TEST_F(SingleClientSharedTabGroupVersioningSyncTest, + ShouldShowVersioningMessagesAfterRestart) { + // Restart chrome with version updated. + const base::Uuid group_guid = base::Uuid::GenerateRandomV4(); + const syncer::CollaborationId kCollaborationId("collaboration"); + ASSERT_TRUE(SetupClients()); + + AddSpecificsToFakeServer( + MakeSharedTabGroupSpecifics( + group_guid, + /*originating_saved_group_guid=*/base::Uuid::GenerateRandomV4(), + "title", sync_pb::SharedTabGroup_Color_CYAN), + kCollaborationId); + AddSpecificsToFakeServer( + MakeSharedTabGroupTabSpecifics(base::Uuid::GenerateRandomV4(), group_guid, + "tab 1", GURL("http://google.com/1")), + kCollaborationId); + AddSpecificsToFakeServer( + MakeSharedTabGroupTabSpecifics(base::Uuid::GenerateRandomV4(), group_guid, + "tab 2", GURL("http://google.com/2")), + kCollaborationId); + + ASSERT_TRUE(SetupSync()); + RegisterCollaboration(kCollaborationId); + + ASSERT_THAT(GetAllTabGroups(), SizeIs(1)); + + VersioningMessageController* versioning_message_controller = + GetTabGroupSyncService()->GetVersioningMessageController(); + EXPECT_FALSE( + ExpectMessageUiShouldBeShown(versioning_message_controller, + VersioningMessageController::MessageType:: + VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE)); + EXPECT_TRUE(ExpectMessageUiShouldBeShown( + versioning_message_controller, + VersioningMessageController::MessageType::VERSION_UPDATED_MESSAGE)); +} + #endif // !BUILDFLAG(IS_ANDROID) } // namespace
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 5c89e976..82fecd04 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -4743,6 +4743,9 @@ "views/web_apps/web_app_identity_update_confirmation_view.h", "views/web_apps/web_app_install_dialog_delegate.cc", "views/web_apps/web_app_install_dialog_delegate.h", + "views/web_apps/web_app_launch_dialog.cc", + "views/web_apps/web_app_modal_dialog_delegate.cc", + "views/web_apps/web_app_modal_dialog_delegate.h", "views/web_apps/web_app_simple_install_dialog.cc", "views/web_apps/web_app_uninstall_dialog_view.cc", "views/web_apps/web_app_uninstall_dialog_view.h",
diff --git a/chrome/browser/ui/android/edge_to_edge/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeUtils.java b/chrome/browser/ui/android/edge_to_edge/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeUtils.java index bc308b7..1041f58 100644 --- a/chrome/browser/ui/android/edge_to_edge/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeUtils.java +++ b/chrome/browser/ui/android/edge_to_edge/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeUtils.java
@@ -122,7 +122,7 @@ * <p>When enabled, Chrome will replace the OS navigation bar with a thin "Chin" layer in the * browser controls and can be scrolled off the screen on web pages. */ - static boolean isBottomChinFeatureEnabled() { + public static boolean isBottomChinFeatureEnabled() { return ChromeFeatureList.sEdgeToEdgeBottomChin.isEnabled(); }
diff --git a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManager.java b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManager.java index d6fdf0a..34e64ea 100644 --- a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManager.java +++ b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManager.java
@@ -18,6 +18,7 @@ import org.chromium.chrome.browser.tabmodel.TabGroupMetadata; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabModelObserver; +import org.chromium.components.messages.MessageDispatcher; import java.util.ArrayList; import java.util.Collections; @@ -210,6 +211,19 @@ // Not implemented } + /** + * Shows a message to notify the user when excess of {@link MultiWindowUtils#getMaxInstances()} + * running activities have been finished after an instance limit downgrade causing existence of + * more active instances than the instance limit. + * + * @param messageDispatcher The {@link MessageDispatcher} to enqueue the instance restoration + * message. + * @return {@code true} if the instance restoration message was shown, {@code false} otherwise. + */ + public boolean showInstanceRestorationMessage(@Nullable MessageDispatcher messageDispatcher) { + return false; + } + public abstract void setCurrentDisplayIdForTesting(int displayId); public abstract @Nullable DisplayManager.DisplayListener getDisplayListenerForTesting();
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessor.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessor.java index 8ad3144..5401823e 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessor.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessor.java
@@ -23,6 +23,7 @@ import org.chromium.chrome.browser.omnibox.suggestions.base.BaseSuggestionViewProcessor; import org.chromium.components.omnibox.AutocompleteInput; import org.chromium.components.omnibox.AutocompleteMatch; +import org.chromium.components.omnibox.GroupsProto.GroupId; import org.chromium.components.omnibox.OmniboxSuggestionType; import org.chromium.components.omnibox.SuggestTemplateInfoProto.SuggestTemplateInfo; import org.chromium.components.omnibox.suggestions.OmniboxSuggestionUiType; @@ -191,6 +192,9 @@ } protected @Nullable SuggestionSpannable getSuggestionDescription(AutocompleteMatch match) { + if (match.getGroupId() == GroupId.GROUP_PERSONALIZED_ZERO_SUGGEST_WITH_MIA.getNumber()) { + return new SuggestionSpannable(match.getDescription()); + } return null; }
diff --git a/chrome/browser/ui/android/signin/java/res/layout/batch_upload_dialog_view.xml b/chrome/browser/ui/android/signin/java/res/layout/batch_upload_dialog_view.xml index 05d1ec25..73643a4 100644 --- a/chrome/browser/ui/android/signin/java/res/layout/batch_upload_dialog_view.xml +++ b/chrome/browser/ui/android/signin/java/res/layout/batch_upload_dialog_view.xml
@@ -17,14 +17,6 @@ android:orientation="vertical" android:id="@+id/batch_upload_dialog"> - <TextView - android:id="@android:id/message" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginBottom="16dp" - android:text="@string/batch_upload_dialog_description" - android:textAppearance="@style/TextAppearance.TextMedium.Secondary"/> - <org.chromium.components.browser_ui.widget.MaterialSwitchWithTitleAndSummary android:id="@+id/batch_upload_dialog_bookmarks" android:layout_width="match_parent"
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd index 2296900..2c3a79f 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -2699,37 +2699,37 @@ </message> <message name="IDS_BATCH_UPLOAD_CARD_DESCRIPTION_PASSWORD" desc="This message appears in a user's settings for signing in to Chrome with their Google Account. The text appears in a temporary card to inform them that there is some local data (passwords) saved to their device, but the data hasn't been saved to their Google Account yet. The user can click 'Save in Account' to enter a flow where they review the data and choose to save it in their account. When data is saved to the user's Google Account, it's backed up safely and is available on any device where they're signed in to Chrome."> {PASSWORDS_COUNT, plural, - =1 {1 password is saved only to this device. To use it on your other devices, save it in your Google Account, <ph name="ACCOUNT_EMAIL">%2$s<ex>elisa.g.beckett@gmail.com</ex></ph>.} - other {# passwords are saved only to this device. To use them on your other devices, save them in your Google Account, <ph name="ACCOUNT_EMAIL">%2$s<ex>elisa.g.beckett@gmail.com</ex></ph>.}} + =1 {1 password is saved only to this device. To use it on your other devices, save it in your Google Account.} + other {# passwords are saved only to this device. To use them on your other devices, save them in your Google Account.}} </message> <message name="IDS_BATCH_UPLOAD_CARD_DESCRIPTION_PASSWORD_AND_OTHER" desc="This message appears in a user's settings for signing in to Chrome with their Google Account. The text appears in a temporary card to inform them that there is some local data (bookmarks, or other data) saved to their device, but the data hasn't been saved to their Google Account yet. The user can click 'Save in Account' to enter a flow where they review the data and choose to save it in their account. When data is saved to the user's Google Account, it's backed up safely and is available on any device where they're signed in to Chrome."> {PASSWORDS_COUNT, plural, - =1 {1 password and other items are saved only to this device. To use them on your other devices, save them in your Google Account, <ph name="ACCOUNT_EMAIL">%2$s<ex>elisa.g.beckett@gmail.com</ex></ph>.} - other {# passwords and other items are saved only to this device. To use them on your other devices, save them in your Google Account, <ph name="ACCOUNT_EMAIL">%2$s<ex>elisa.g.beckett@gmail.com</ex></ph>.}} + =1 {1 password and other items are saved only to this device. To use them on your other devices, save them in your Google Account.} + other {# passwords and other items are saved only to this device. To use them on your other devices, save them in your Google Account.}} </message> <message name="IDS_BATCH_UPLOAD_CARD_DESCRIPTION_OTHER" desc="This message appears either in user's account settings or bookmark manager. The text appears in a temporary card to inform them that there is some local data (in case of the account settings card the local data does not include passwords, and in case of the bookmark manager card the local data does not include bookmarks) saved to their device, but the data hasn't been saved to their Google Account yet. The user can click 'Save in Account' to enter a flow where they review the data and choose to save it in their account. When data is saved to the user's Google Account, it's backed up safely and is available on any device where they're signed in to Chrome."> {ITEMS_COUNT, plural, - =1 {1 item is saved only to this device. To use it on your other devices, save it in your Google Account, <ph name="ACCOUNT_EMAIL">%2$s<ex>elisa.g.beckett@gmail.com</ex></ph>.} - other {# items are saved only to this device. To use them on your other devices, save them in your Google Account, <ph name="ACCOUNT_EMAIL">%2$s<ex>elisa.g.beckett@gmail.com</ex></ph>.}} + =1 {1 item is saved only to this device. To use it on your other devices, save it in your Google Account.} + other {# items are saved only to this device. To use them on your other devices, save them in your Google Account.}} </message> <message name="IDS_BATCH_UPLOAD_CARD_SAVE_BUTTON" desc="This message appears on a button in a temporary card to inform the user that there is some local data saved to their device, but the data hasn't been saved to their Google Account yet. The user can click 'Save in Account' to enter a flow where they review the data and choose to save it in their account. When data is saved to the user's Google Account, it's backed up safely and is available on any device where they're signed in to Chrome."> Save in account </message> <message name="IDS_BATCH_UPLOAD_CARD_DESCRIPTION_BOOKMARK" desc="This message appears in a user's bookmark manager. The text appears in a temporary card to inform them that there is some local data (bookmarks) saved to their device, but the data hasn't been saved to their Google Account yet. The user can click 'Save in Account' to enter a flow where they review the data and choose to save it in their account. When data is saved to the user's Google Account, it's backed up safely and is available on any device where they're signed in to Chrome."> {BOOKMARKS_COUNT, plural, - =1 {1 bookmark is saved only to this device. To use it on your other devices, save it in your Google Account, <ph name="ACCOUNT_EMAIL">%2$s<ex>elisa.g.beckett@gmail.com</ex></ph>.} - other {# bookmarks are saved only to this device. To use them on your other devices, save them in your Google Account, <ph name="ACCOUNT_EMAIL">%2$s<ex>elisa.g.beckett@gmail.com</ex></ph>.}} + =1 {1 bookmark is saved only to this device. To use it on your other devices, save it in your Google Account.} + other {# bookmarks are saved only to this device. To use them on your other devices, save them in your Google Account.}} </message> <message name="IDS_BATCH_UPLOAD_CARD_DESCRIPTION_BOOKMARK_AND_OTHER" desc="This message appears in a user's bookmark manager. The text appears in a temporary card to inform them that there is some local data (bookmarks and some other data) saved to their device, but the data hasn't been saved to their Google Account yet. The user can click 'Save in Account' to enter a flow where they review the data and choose to save it in their account. When data is saved to the user's Google Account, it's backed up safely and is available on any device where they're signed in to Chrome."> {BOOKMARKS_COUNT, plural, - =1 {1 bookmark and other items are saved only to this device. To use them on your other devices, save them in your Google Account, <ph name="ACCOUNT_EMAIL">%2$s<ex>elisa.g.beckett@gmail.com</ex></ph>.} - other {# bookmarks and other items are saved only to this device. To use them on your other devices, save them in your Google Account, <ph name="ACCOUNT_EMAIL">%2$s<ex>elisa.g.beckett@gmail.com</ex></ph>.}} + =1 {1 bookmark and other items are saved only to this device. To use them on your other devices, save them in your Google Account.} + other {# bookmarks and other items are saved only to this device. To use them on your other devices, save them in your Google Account.}} </message> <message name="IDS_BATCH_UPLOAD_DIALOG_TITLE" desc="The text appears as the title of a confirmation dialog where the user can choose to save some data to their Google Account. When data is saved to the Google Account, it's backed up safely and is available on any device where they're signed in to Chrome."> Save data in your Google Account </message> <message name="IDS_BATCH_UPLOAD_DIALOG_DESCRIPTION" desc="The text appears as a note in a confirmation dialog where the user can choose to save some data to their Google Account. When data is saved to the Google Account, it's backed up safely and is available on any device where they're signed in to Chrome. This note explains where the user can go to view and manage individual items. like individual bookmarks or passwords."> - You can also view and manage these items in your bookmarks, reading list, or password manager + You can choose what data to save in your Google Account, <ph name="ACCOUNT_EMAIL">%1$s<ex>elisa.g.beckett@gmail.com</ex></ph>.\nYou can also view and manage these items in your bookmarks, reading list, or password manager </message> <message name="IDS_BATCH_UPLOAD_DIALOG_BOOKMARKS" desc="One of the data types that we allow uploading through a confirmation dialog where the user can choose to save some data to their Google Account. When data is saved to the Google Account, it's backed up safely and is available on any device where they're signed in to Chrome."> {ITEMS_COUNT, plural,
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_BATCH_UPLOAD_CARD_DESCRIPTION_BOOKMARK.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_BATCH_UPLOAD_CARD_DESCRIPTION_BOOKMARK.png.sha1 index 9054395..968fd59 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_BATCH_UPLOAD_CARD_DESCRIPTION_BOOKMARK.png.sha1 +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_BATCH_UPLOAD_CARD_DESCRIPTION_BOOKMARK.png.sha1
@@ -1 +1 @@ -c60b1eaa999d3009982c5cc740ba1271a5d51068 \ No newline at end of file +8c56b92363b755b3ed47fb80d28319bbd38719c7 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_BATCH_UPLOAD_CARD_DESCRIPTION_BOOKMARK_AND_OTHER.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_BATCH_UPLOAD_CARD_DESCRIPTION_BOOKMARK_AND_OTHER.png.sha1 index 1a79539..15409b6 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_BATCH_UPLOAD_CARD_DESCRIPTION_BOOKMARK_AND_OTHER.png.sha1 +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_BATCH_UPLOAD_CARD_DESCRIPTION_BOOKMARK_AND_OTHER.png.sha1
@@ -1 +1 @@ -fdf3bae84ea614886aead0d7a51963c032b44216 \ No newline at end of file +f5b2e836490e0fe511805c395fdf4eaaaa2420cd \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_BATCH_UPLOAD_CARD_DESCRIPTION_OTHER.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_BATCH_UPLOAD_CARD_DESCRIPTION_OTHER.png.sha1 index f2bd20d..aa118935 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_BATCH_UPLOAD_CARD_DESCRIPTION_OTHER.png.sha1 +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_BATCH_UPLOAD_CARD_DESCRIPTION_OTHER.png.sha1
@@ -1 +1 @@ -05b77d3f2aefb3aedbc875366975c01254946e58 \ No newline at end of file +3a72abe1c2cbca79364d7d8c9894fa95340f5633 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_BATCH_UPLOAD_CARD_DESCRIPTION_PASSWORD.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_BATCH_UPLOAD_CARD_DESCRIPTION_PASSWORD.png.sha1 index 3511659a..372a9541 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_BATCH_UPLOAD_CARD_DESCRIPTION_PASSWORD.png.sha1 +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_BATCH_UPLOAD_CARD_DESCRIPTION_PASSWORD.png.sha1
@@ -1 +1 @@ -715ddcf5554ac18452509e8469d6b9a39c5ec710 \ No newline at end of file +916f8421f0a8455e063870cf425e44404f2ce1ad \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_BATCH_UPLOAD_CARD_DESCRIPTION_PASSWORD_AND_OTHER.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_BATCH_UPLOAD_CARD_DESCRIPTION_PASSWORD_AND_OTHER.png.sha1 index 570219b..22aa41d 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_BATCH_UPLOAD_CARD_DESCRIPTION_PASSWORD_AND_OTHER.png.sha1 +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_BATCH_UPLOAD_CARD_DESCRIPTION_PASSWORD_AND_OTHER.png.sha1
@@ -1 +1 @@ -948cf77748f7339ad9a3760517746a71672d75be \ No newline at end of file +97f20acd38dea42e44701c542450669c2e865f1e \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_BATCH_UPLOAD_DIALOG_DESCRIPTION.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_BATCH_UPLOAD_DIALOG_DESCRIPTION.png.sha1 index bf5d2415..04fef641 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_BATCH_UPLOAD_DIALOG_DESCRIPTION.png.sha1 +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_BATCH_UPLOAD_DIALOG_DESCRIPTION.png.sha1
@@ -1 +1 @@ -7ed5de00cc9098fc29d658c3f33e9f5a9cb698f0 \ No newline at end of file +a8627703fdce0aecc3c6b98867fa4ab3dd260928 \ No newline at end of file
diff --git a/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/SurfaceColorUpdateUtils.java b/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/SurfaceColorUpdateUtils.java index cb4d04d8..488c866 100644 --- a/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/SurfaceColorUpdateUtils.java +++ b/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/SurfaceColorUpdateUtils.java
@@ -42,8 +42,10 @@ return ChromeFeatureList.sAndroidSurfaceColorUpdate.isEnabled(); } + /** Whether new GM3 colors are being used for the tab group colors. */ public static boolean useNewGm3GtsTabGroupColors() { - return ChromeFeatureList.sAndroidTabGroupsColorUpdateGm3.isEnabled(); + return ChromeFeatureList.sAndroidTabGroupsColorUpdateGm3.isEnabled() + || ThemeModuleUtils.isForceEnableDependencies(); } /** @@ -85,9 +87,7 @@ if (useNewToolbarSurfaceColor()) { return SemanticColorUtils.getColorSurfaceDim(context); } - @ColorInt int darkThemeColor = SemanticColorUtils.getColorSurfaceContainer(context); - @ColorInt int lightThemeColor = SemanticColorUtils.getColorSurfaceContainerHigh(context); - return ColorUtils.inNightMode(context) ? darkThemeColor : lightThemeColor; + return SemanticColorUtils.getColorSurfaceContainerHigh(context); } /**
diff --git a/chrome/browser/ui/safety_hub/notification_permission_review_result.h b/chrome/browser/ui/safety_hub/notification_permission_review_result.h index 4784e16..cc327a8 100644 --- a/chrome/browser/ui/safety_hub/notification_permission_review_result.h +++ b/chrome/browser/ui/safety_hub/notification_permission_review_result.h
@@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_UI_SAFETY_HUB_NOTIFICATION_PERMISSION_REVIEW_RESULT_H_ #define CHROME_BROWSER_UI_SAFETY_HUB_NOTIFICATION_PERMISSION_REVIEW_RESULT_H_ +#include <set> + #include "chrome/browser/ui/safety_hub/safety_hub_service.h" #include "components/content_settings/core/browser/host_content_settings_map.h"
diff --git a/chrome/browser/ui/tabs/organization/tab_declutter_controller.cc b/chrome/browser/ui/tabs/organization/tab_declutter_controller.cc index 5a63f2c..f1b479d 100644 --- a/chrome/browser/ui/tabs/organization/tab_declutter_controller.cc +++ b/chrome/browser/ui/tabs/organization/tab_declutter_controller.cc
@@ -28,6 +28,7 @@ #include "components/tabs/public/tab_interface.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/navigation_entry.h" +#include "content/public/browser/web_contents.h" #include "url/gurl.h" namespace tabs {
diff --git a/chrome/browser/ui/tabs/tab_collection_storage_unittest.cc b/chrome/browser/ui/tabs/tab_collection_storage_unittest.cc index 5b649ac1..9d9cb86 100644 --- a/chrome/browser/ui/tabs/tab_collection_storage_unittest.cc +++ b/chrome/browser/ui/tabs/tab_collection_storage_unittest.cc
@@ -20,6 +20,7 @@ #include "components/tabs/public/tab_collection.h" #include "components/tabs/public/tab_group_tab_collection.h" #include "components/tabs/public/unpinned_tab_collection.h" +#include "content/public/browser/web_contents.h" #include "content/public/test/browser_task_environment.h" #include "content/public/test/test_renderer_host.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ui/tabs/tab_collection_unittest.cc b/chrome/browser/ui/tabs/tab_collection_unittest.cc index dec876f..707b484 100644 --- a/chrome/browser/ui/tabs/tab_collection_unittest.cc +++ b/chrome/browser/ui/tabs/tab_collection_unittest.cc
@@ -27,6 +27,7 @@ #include "components/tabs/public/tab_group_tab_collection.h" #include "components/tabs/public/tab_strip_collection.h" #include "components/tabs/public/unpinned_tab_collection.h" +#include "content/public/browser/web_contents.h" #include "content/public/test/browser_task_environment.h" #include "content/public/test/test_renderer_host.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ui/tabs/tab_model.cc b/chrome/browser/ui/tabs/tab_model.cc index 4a7faea7..5ec6066 100644 --- a/chrome/browser/ui/tabs/tab_model.cc +++ b/chrome/browser/ui/tabs/tab_model.cc
@@ -27,6 +27,7 @@ #include "components/web_modal/modal_dialog_host.h" #include "components/web_modal/web_contents_modal_dialog_host.h" #include "content/public/browser/visibility.h" +#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_user_data.h" #include "third_party/perfetto/include/perfetto/tracing/traced_value.h" #include "ui/views/widget/native_widget.h"
diff --git a/chrome/browser/ui/tabs/tab_model.h b/chrome/browser/ui/tabs/tab_model.h index 9485531..1668ff2 100644 --- a/chrome/browser/ui/tabs/tab_model.h +++ b/chrome/browser/ui/tabs/tab_model.h
@@ -15,9 +15,12 @@ #include "components/tab_groups/tab_group_id.h" #include "components/tabs/public/split_tab_id.h" #include "components/tabs/public/tab_interface.h" -#include "content/public/browser/web_contents.h" #include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h" +namespace content { +class WebContents; +} + class TabStripModel; namespace tabs {
diff --git a/chrome/browser/ui/tabs/tab_strip_model_stats_recorder.cc b/chrome/browser/ui/tabs/tab_strip_model_stats_recorder.cc index cc19277..c1af5df 100644 --- a/chrome/browser/ui/tabs/tab_strip_model_stats_recorder.cc +++ b/chrome/browser/ui/tabs/tab_strip_model_stats_recorder.cc
@@ -15,6 +15,7 @@ #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_tab_strip_tracker.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "content/public/browser/web_contents.h" TabStripModelStatsRecorder::TabStripModelStatsRecorder() : browser_tab_strip_tracker_(
diff --git a/chrome/browser/ui/views/web_apps/web_app_install_dialog_delegate.cc b/chrome/browser/ui/views/web_apps/web_app_install_dialog_delegate.cc index f33d498b..125b0f3 100644 --- a/chrome/browser/ui/views/web_apps/web_app_install_dialog_delegate.cc +++ b/chrome/browser/ui/views/web_apps/web_app_install_dialog_delegate.cc
@@ -13,10 +13,8 @@ #include "base/observer_list_internal.h" #include "base/strings/string_util.h" #include "base/task/sequenced_task_runner.h" -#include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/page_action/page_action_icon_type.h" -#include "chrome/browser/ui/views/extensions/security_dialog_tracker.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/frame/toolbar_button_provider.h" #include "chrome/browser/ui/views/page_action/page_action_icon_view.h" @@ -30,7 +28,6 @@ #include "components/webapps/browser/installable/ml_install_operation_tracker.h" #include "content/public/browser/page.h" #include "content/public/browser/web_contents.h" -#include "content/public/browser/web_contents_observer.h" #include "ui/base/interaction/element_tracker.h" #include "ui/views/controls/textfield/textfield.h" #include "ui/views/interaction/element_tracker_views.h" @@ -96,8 +93,7 @@ PrefService* prefs, feature_engagement::Tracker* tracker, InstallDialogType dialog_type) - : content::WebContentsObserver(web_contents), - web_contents_(web_contents), + : WebAppModalDialogDelegate(web_contents), install_info_(std::move(web_app_info)), install_tracker_(std::move(install_tracker)), callback_(std::move(callback)), @@ -111,8 +107,11 @@ } WebAppInstallDialogDelegate::~WebAppInstallDialogDelegate() { + if (!web_contents()) { + return; + } // TODO(crbug.com/40841129): move this to dialog->SetHighlightedButton. - Browser* browser = chrome::FindBrowserWithTab(web_contents_); + Browser* browser = chrome::FindBrowserWithTab(web_contents()); if (!browser) { return; } @@ -130,14 +129,6 @@ } } -void WebAppInstallDialogDelegate::OnWidgetShownStartTracking( - views::Widget* install_dialog_widget) { - occlusion_observation_.Observe(install_dialog_widget); - widget_observation_.Observe(install_dialog_widget); - extensions::SecurityDialogTracker::GetInstance()->AddSecurityDialog( - install_dialog_widget); -} - void WebAppInstallDialogDelegate::OnAccept() { MeasureAcceptUserActionsForInstallDialog(); if (iph_state_ == PwaInProductHelpState::kShown) { @@ -239,29 +230,6 @@ /*enabled=*/!text_field_contents.empty()); } -void WebAppInstallDialogDelegate::OnVisibilityChanged( - content::Visibility visibility) { - if (visibility != content::Visibility::VISIBLE) { - CloseDialogAsIgnored(); - } -} - -void WebAppInstallDialogDelegate::WebContentsDestroyed() { - CloseDialogAsIgnored(); -} - -void WebAppInstallDialogDelegate::PrimaryPageChanged(content::Page& page) { - CloseDialogAsIgnored(); -} - -void WebAppInstallDialogDelegate::OnOcclusionStateChanged(bool occluded) { - // If a picture-in-picture window is occluding the dialog, force it to close - // to prevent spoofing. - if (occluded) { - PictureInPictureWindowManager::GetInstance()->ExitPictureInPicture(); - } -} - void WebAppInstallDialogDelegate::OnWidgetBoundsChanged( views::Widget* widget, const gfx::Rect& new_bounds) { @@ -273,10 +241,6 @@ } } -void WebAppInstallDialogDelegate::OnWidgetDestroyed(views::Widget* widget) { - widget_observation_.Reset(); -} - void WebAppInstallDialogDelegate::CloseDialogAsIgnored() { if (!dialog_model() || !dialog_model()->host()) { return;
diff --git a/chrome/browser/ui/views/web_apps/web_app_install_dialog_delegate.h b/chrome/browser/ui/views/web_apps/web_app_install_dialog_delegate.h index 459d47e..9c956d9 100644 --- a/chrome/browser/ui/views/web_apps/web_app_install_dialog_delegate.h +++ b/chrome/browser/ui/views/web_apps/web_app_install_dialog_delegate.h
@@ -10,24 +10,16 @@ #include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" -#include "chrome/browser/picture_in_picture/picture_in_picture_occlusion_observer.h" -#include "chrome/browser/picture_in_picture/scoped_picture_in_picture_occlusion_observation.h" +#include "chrome/browser/ui/views/web_apps/web_app_modal_dialog_delegate.h" #include "chrome/browser/ui/web_applications/web_app_dialogs.h" #include "chrome/browser/web_applications/web_app_install_info.h" -#include "content/public/browser/web_contents_observer.h" #include "ui/base/interaction/element_identifier.h" #include "ui/base/interaction/element_tracker.h" #include "ui/base/models/dialog_model.h" #include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_observer.h" class PrefService; -namespace content { -class Page; -class WebContents; -} // namespace content - namespace feature_engagement { class Tracker; } @@ -75,10 +67,7 @@ // irrespective of the size of the browser window triggering it. bool IsWidgetCurrentSizeSmallerThanPreferredSize(views::Widget* widget); -class WebAppInstallDialogDelegate : public ui::DialogModelDelegate, - public content::WebContentsObserver, - public PictureInPictureOcclusionObserver, - public views::WidgetObserver { +class WebAppInstallDialogDelegate : public WebAppModalDialogDelegate { public: DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kDiyAppsDialogOkButtonId); DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kPwaInstallDialogInstallButton); @@ -96,13 +85,6 @@ ~WebAppInstallDialogDelegate() override; - // Once the install dialog is shown, start tracking the widget for: - // 1. Observing it to prevent picture in picture occlusion. - // 2. Observing it for size changes so that it can be closed if needed. - // 3. Tracking it as a security dialog so that extension popups do not appear - // over it. - void OnWidgetShownStartTracking(views::Widget* install_dialog_widget); - void OnAccept(); void OnCancel(); void OnClose(); @@ -121,27 +103,17 @@ return weak_ptr_factory_.GetWeakPtr(); } - // content::WebContentsObserver overrides: - void OnVisibilityChanged(content::Visibility visibility) override; - void WebContentsDestroyed() override; - void PrimaryPageChanged(content::Page& page) override; - - // PictureInPictureOcclusionObserver overrides: - void OnOcclusionStateChanged(bool occluded) override; - // views::WidgetObserver overrides: void OnWidgetBoundsChanged(views::Widget* widget, const gfx::Rect& new_bounds) override; - void OnWidgetDestroyed(views::Widget* widget) override; - - void CloseDialogAsIgnored(); + // WebAppModalDialogDelegate overrides: + void CloseDialogAsIgnored() override; private: void MeasureIphOnDialogClose(); void MeasureAcceptUserActionsForInstallDialog(); void MeasureCancelUserActionsForInstallDialog(); - raw_ptr<content::WebContents> web_contents_; std::unique_ptr<WebAppInstallInfo> install_info_; std::unique_ptr<webapps::MlInstallOperationTracker> install_tracker_; AppInstallationAcceptanceCallback callback_; @@ -151,10 +123,6 @@ InstallDialogType dialog_type_; std::u16string text_field_contents_; bool received_user_response_ = false; - ScopedPictureInPictureOcclusionObservation occlusion_observation_{this}; - base::ScopedObservation<views::Widget, views::WidgetObserver> - widget_observation_{this}; - base::WeakPtrFactory<WebAppInstallDialogDelegate> weak_ptr_factory_{this}; };
diff --git a/chrome/browser/ui/views/web_apps/web_app_launch_dialog.cc b/chrome/browser/ui/views/web_apps/web_app_launch_dialog.cc new file mode 100644 index 0000000..940f8b0 --- /dev/null +++ b/chrome/browser/ui/views/web_apps/web_app_launch_dialog.cc
@@ -0,0 +1,171 @@ +// 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 "base/auto_reset.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/apps/app_service/app_launch_params.h" +#include "chrome/browser/picture_in_picture/picture_in_picture_occlusion_observer.h" +#include "chrome/browser/picture_in_picture/scoped_picture_in_picture_occlusion_observation.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/views/extensions/security_dialog_tracker.h" +#include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/browser/ui/web_applications/web_app_dialogs.h" +#include "chrome/browser/web_applications/commands/launch_web_app_command.h" +#include "chrome/browser/web_applications/web_app_command_manager.h" +#include "chrome/browser/web_applications/web_app_constants.h" +#include "chrome/browser/web_applications/web_app_provider.h" +#include "chrome/browser/web_applications/web_app_ui_manager.h" +#include "chrome/common/chrome_features.h" +#include "chrome/grit/generated_resources.h" +#include "components/constrained_window/constrained_window_views.h" +#include "components/web_modal/web_contents_modal_dialog_manager.h" +#include "content/public/browser/web_contents.h" +#include "third_party/blink/public/mojom/web_install/web_install.mojom.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/mojom/dialog_button.mojom.h" +#include "ui/base/mojom/ui_base_types.mojom-shared.h" +#include "ui/views/bubble/bubble_dialog_model_host.h" +#include "ui/views/view.h" +#include "ui/views/view_class_properties.h" +#include "ui/views/view_utils.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_observer.h" +#include "web_app_modal_dialog_delegate.h" + +namespace web_app { + +DEFINE_ELEMENT_IDENTIFIER_VALUE(kWebInstallLaunchDialogAppName); +using WebAppBackgroundAppLaunchAcceptanceCallback = + base::OnceCallback<void(bool accepted)>; + +namespace { +bool g_auto_accept_launch_for_testing = false; +} // namespace + +class WebAppLaunchDialogDelegate : public WebAppModalDialogDelegate { + public: + WebAppLaunchDialogDelegate( + content::WebContents* web_contents, + WebAppBackgroundAppLaunchAcceptanceCallback callback, + webapps::AppId app_id, + Profile* profile) + : WebAppModalDialogDelegate(web_contents), + callback_(std::move(callback)), + app_id_(app_id), + profile_(profile) {} + + ~WebAppLaunchDialogDelegate() override = default; + + void OnAccept() { + std::move(callback_).Run(/*accepted=*/true); + + WebAppProvider* provider = WebAppProvider::GetForWebApps(profile_); + if (provider) { + apps::AppLaunchParams params( + app_id_, apps::LaunchContainer::kLaunchContainerWindow, + WindowOpenDisposition::NEW_WINDOW, + apps::LaunchSource::kFromWebInstallApi); + + provider->command_manager().ScheduleCommand( + std::make_unique<LaunchWebAppCommand>( + profile_, provider, std::move(params), + LaunchWebAppWindowSetting::kUseLaunchParams, base::DoNothing())); + } + } + + void OnCancel() { std::move(callback_).Run(/*accepted=*/false); } + + void OnDestroyed() { + if (!callback_.is_null()) { + std::move(callback_).Run(/*accepted=*/false); + } + } + + void CloseDialogAsIgnored() override { + if (!dialog_model() || !dialog_model()->host()) { + return; + } + dialog_model()->host()->Close(); + } + + base::WeakPtr<WebAppLaunchDialogDelegate> AsWeakPtr() { + return weak_ptr_factory_.GetWeakPtr(); + } + + private: + WebAppBackgroundAppLaunchAcceptanceCallback callback_; + webapps::AppId app_id_; + raw_ptr<Profile> profile_; + + base::WeakPtrFactory<WebAppLaunchDialogDelegate> weak_ptr_factory_{this}; +}; + +void ShowWebInstallAppLaunchDialog( + content::WebContents* web_contents, + const webapps::AppId& app_id, + Profile* profile, + std::string app_name, + WebAppBackgroundAppLaunchAcceptanceCallback callback) { + Browser* browser = chrome::FindBrowserWithTab(web_contents); + if (!browser) { + std::move(callback).Run(/*accepted=*/false); + return; + } + + // Do not show the dialog if it is already being shown. + const web_modal::WebContentsModalDialogManager* manager = + web_modal::WebContentsModalDialogManager::FromWebContents(web_contents); + if (!manager || manager->IsDialogActive()) { + std::move(callback).Run(/*accepted=*/false); + return; + } + + views::BubbleDialogDelegate* dialog_delegate = nullptr; + + auto delegate = std::make_unique<WebAppLaunchDialogDelegate>( + web_contents, std::move(callback), app_id, profile); + auto delegate_weak_ptr = delegate->AsWeakPtr(); + + auto dialog_model = + ui::DialogModel::Builder(std::move(delegate)) + .SetInternalName("WebInstallLaunchDialog") + .SetTitle(l10n_util::GetStringUTF16( + IDS_INTENT_PICKER_BUBBLE_VIEW_OPEN_WITH)) + // TODO(crbug.com/422940463): Show app icon in new launch dialog for + // background document launches. + // This paragraph is a placeholder for now. + .AddParagraph(ui::DialogModelLabel(base::UTF8ToUTF16(app_name))) + .AddOkButton(base::BindOnce(&WebAppLaunchDialogDelegate::OnAccept, + delegate_weak_ptr), + ui::DialogModel::Button::Params().SetLabel( + l10n_util::GetStringUTF16( + IDS_INTENT_PICKER_BUBBLE_VIEW_OPEN))) + .AddCancelButton(base::BindOnce(&WebAppLaunchDialogDelegate::OnCancel, + delegate_weak_ptr)) + .SetCloseActionCallback(base::BindOnce( + &WebAppLaunchDialogDelegate::OnCancel, delegate_weak_ptr)) + .SetDialogDestroyingCallback(base::BindOnce( + &WebAppLaunchDialogDelegate::OnDestroyed, delegate_weak_ptr)) + .OverrideDefaultButton(ui::mojom::DialogButton::kCancel) + .Build(); + auto dialog = views::BubbleDialogModelHost::CreateModal( + std::move(dialog_model), ui::mojom::ModalType::kChild); + + dialog_delegate = dialog->AsBubbleDialogDelegate(); + views::Widget* launch_dialog_widget = + constrained_window::ShowWebModalDialogViews(dialog.release(), + web_contents); + delegate_weak_ptr->OnWidgetShownStartTracking(launch_dialog_widget); + + if (g_auto_accept_launch_for_testing) { + dialog_delegate->AcceptDialog(); + } +} + +base::AutoReset<bool> SetAutoAcceptWebInstallLaunchDialogForTesting() { + return base::AutoReset<bool>(&g_auto_accept_launch_for_testing, true); +} + +} // namespace web_app
diff --git a/chrome/browser/ui/views/web_apps/web_app_modal_dialog_delegate.cc b/chrome/browser/ui/views/web_apps/web_app_modal_dialog_delegate.cc new file mode 100644 index 0000000..6c74ab5 --- /dev/null +++ b/chrome/browser/ui/views/web_apps/web_app_modal_dialog_delegate.cc
@@ -0,0 +1,55 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/web_apps/web_app_modal_dialog_delegate.h" + +#include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/views/extensions/security_dialog_tracker.h" +#include "ui/views/widget/widget.h" + +namespace web_app { + +WebAppModalDialogDelegate::WebAppModalDialogDelegate( + content::WebContents* web_contents) + : content::WebContentsObserver(web_contents) {} + +WebAppModalDialogDelegate::~WebAppModalDialogDelegate() = default; + +void WebAppModalDialogDelegate::OnWidgetShownStartTracking( + views::Widget* dialog_widget) { + occlusion_observation_.Observe(dialog_widget); + widget_observation_.Observe(dialog_widget); + extensions::SecurityDialogTracker::GetInstance()->AddSecurityDialog( + dialog_widget); +} + +void WebAppModalDialogDelegate::OnVisibilityChanged( + content::Visibility visibility) { + if (visibility != content::Visibility::VISIBLE) { + CloseDialogAsIgnored(); + } +} + +void WebAppModalDialogDelegate::WebContentsDestroyed() { + CloseDialogAsIgnored(); +} + +void WebAppModalDialogDelegate::PrimaryPageChanged(content::Page& page) { + CloseDialogAsIgnored(); +} + +void WebAppModalDialogDelegate::OnWidgetDestroyed(views::Widget* widget) { + widget_observation_.Reset(); +} + +void WebAppModalDialogDelegate::OnOcclusionStateChanged(bool occluded) { + // If a picture-in-picture window is occluding the dialog, force it to close + // to prevent spoofing. + if (occluded) { + PictureInPictureWindowManager::GetInstance()->ExitPictureInPicture(); + } +} + +} // namespace web_app
diff --git a/chrome/browser/ui/views/web_apps/web_app_modal_dialog_delegate.h b/chrome/browser/ui/views/web_apps/web_app_modal_dialog_delegate.h new file mode 100644 index 0000000..70e2d85 --- /dev/null +++ b/chrome/browser/ui/views/web_apps/web_app_modal_dialog_delegate.h
@@ -0,0 +1,65 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_VIEWS_WEB_APPS_WEB_APP_MODAL_DIALOG_DELEGATE_H_ +#define CHROME_BROWSER_UI_VIEWS_WEB_APPS_WEB_APP_MODAL_DIALOG_DELEGATE_H_ + +#include "base/memory/raw_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/scoped_observation.h" +#include "chrome/browser/picture_in_picture/picture_in_picture_occlusion_observer.h" +#include "chrome/browser/picture_in_picture/scoped_picture_in_picture_occlusion_observation.h" +#include "content/public/browser/web_contents_observer.h" +#include "ui/base/models/dialog_model.h" +#include "ui/views/widget/widget_observer.h" + +namespace views { +class Widget; +} + +namespace web_app { + +// Base class for modal web app dialogs (install, launch, etc.) +// Covers common functionality for web app modal dialogs, such as closing on +// tab changes, closing on occlusion by the picture in picture dialog, and +// widget destruction. +class WebAppModalDialogDelegate : public ui::DialogModelDelegate, + public content::WebContentsObserver, + public PictureInPictureOcclusionObserver, + public views::WidgetObserver { + public: + explicit WebAppModalDialogDelegate(content::WebContents* web_contents); + ~WebAppModalDialogDelegate() override; + + // Once the dialog is shown, start tracking the widget for: + // 1. Observing it to prevent picture in picture occlusion. + // 2. Observing it for size changes so that it can be closed if needed. + // 3. Tracking it as a security dialog so that extension popups do not appear + // over it. + void OnWidgetShownStartTracking(views::Widget* dialog_widget); + + // content::WebContentsObserver overrides: + void OnVisibilityChanged(content::Visibility visibility) override; + void WebContentsDestroyed() override; + void PrimaryPageChanged(content::Page& page) override; + + // views::WidgetObserver override: + void OnWidgetDestroyed(views::Widget* widget) override; + + // PictureInPictureOcclusionObserver overrides: + void OnOcclusionStateChanged(bool occluded) override; + + protected: + // Handle dialog close due to non-user actions - tab switch, navigation, etc. + virtual void CloseDialogAsIgnored() = 0; + + private: + base::ScopedObservation<views::Widget, views::WidgetObserver> + widget_observation_{this}; + ScopedPictureInPictureOcclusionObservation occlusion_observation_{this}; +}; + +} // namespace web_app + +#endif // CHROME_BROWSER_UI_VIEWS_WEB_APPS_WEB_APP_MODAL_DIALOG_DELEGATE_H_
diff --git a/chrome/browser/ui/web_applications/web_app_dialogs.h b/chrome/browser/ui/web_applications/web_app_dialogs.h index 2ce0e37d..15478d4 100644 --- a/chrome/browser/ui/web_applications/web_app_dialogs.h +++ b/chrome/browser/ui/web_applications/web_app_dialogs.h
@@ -193,6 +193,28 @@ ui::ElementIdentifier id, base::OnceCallback<void(bool)> view_and_element_activated_callback); +// Callback used by the Web Install API to indicate whether the user has +// accepted the launch of a web app. +using WebInstallAppLaunchAcceptanceCallback = + base::OnceCallback<void(bool accepted)>; + +DECLARE_ELEMENT_IDENTIFIER_VALUE(kWebInstallLaunchDialogAppName); + +// Shows a web app launch dialog for `app_id`. Used by the Web Install API. The +// dialog contains the app short name and icon, just like the intent picker. The +// user can accept or cancel the launch. A response is sent via `callback` so +// the service implementation can resolve itself based on the user +// interaction. +void ShowWebInstallAppLaunchDialog( + content::WebContents* web_contents, + const webapps::AppId& app_id, + Profile* profile, + std::string app_name, + WebInstallAppLaunchAcceptanceCallback callback); + +// Sets whether |ShowWebInstallAppLaunchDialog| should accept immediately. +base::AutoReset<bool> SetAutoAcceptWebInstallLaunchDialogForTesting(); + } // namespace web_app #endif // CHROME_BROWSER_UI_WEB_APPLICATIONS_WEB_APP_DIALOGS_H_
diff --git a/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc index 5154f07..dd838ba 100644 --- a/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc +++ b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc
@@ -445,6 +445,16 @@ manifest_id, std::move(callback)); } +void WebAppUiManagerImpl::TriggerLaunchDialogForBackgroundInstall( + content::WebContents* initiating_web_contents, + const webapps::AppId& app_id, + Profile* profile, + const std::string& app_name, + WebInstallAppLaunchAcceptanceCallback callback) { + ShowWebInstallAppLaunchDialog(initiating_web_contents, app_id, profile, + app_name, std::move(callback)); +} + void WebAppUiManagerImpl::PresentUserUninstallDialog( const webapps::AppId& app_id, webapps::WebappUninstallSource uninstall_source,
diff --git a/chrome/browser/ui/web_applications/web_app_ui_manager_impl.h b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.h index c3c752f..fc13195d 100644 --- a/chrome/browser/ui/web_applications/web_app_ui_manager_impl.h +++ b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.h
@@ -147,6 +147,12 @@ const GURL& install_url, const std::optional<GURL>& manifest_id, InstallCallback callback) override; + void TriggerLaunchDialogForBackgroundInstall( + content::WebContents* initiating_web_contents, + const webapps::AppId& app_id, + Profile* profile, + const std::string& app_name, + WebInstallAppLaunchAcceptanceCallback callback) override; void PresentUserUninstallDialog( const webapps::AppId& app_id,
diff --git a/chrome/browser/ui/webui/browser_command/browser_command_handler.cc b/chrome/browser/ui/webui/browser_command/browser_command_handler.cc index 746dff51..2215ea0 100644 --- a/chrome/browser/ui/webui/browser_command/browser_command_handler.cc +++ b/chrome/browser/ui/webui/browser_command/browser_command_handler.cc
@@ -341,9 +341,6 @@ void BrowserCommandHandler::OpenGlic() { #if BUILDFLAG(ENABLE_GLIC) - if (!glic::GlicEnabling::IsEnabledForProfile(profile_)) { - return; - } glic::GlicKeyedService* glic_service = glic::GlicKeyedService::Get(profile_);
diff --git a/chrome/browser/ui/webui/new_tab_footer/new_tab_footer.mojom b/chrome/browser/ui/webui/new_tab_footer/new_tab_footer.mojom index 681ccfc1..7376409 100644 --- a/chrome/browser/ui/webui/new_tab_footer/new_tab_footer.mojom +++ b/chrome/browser/ui/webui/new_tab_footer/new_tab_footer.mojom
@@ -21,10 +21,8 @@ // is managed and the entity managing the browser, which is customizable via // the `EnterpriseCustomLabel` policy. string text; - // Url to the management icon. This will be a default business icon or custom - // icon set by policy. - url.mojom.Url bitmap_data_url; - bool is_custom_logo; + // Url to a custom management icon set by policy. + url.mojom.Url? custom_bitmap_data_url; }; struct BackgroundAttribution {
diff --git a/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler.cc b/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler.cc index e2a7431..6d8516fb 100644 --- a/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler.cc +++ b/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler.cc
@@ -144,11 +144,12 @@ auto notice = new_tab_footer::mojom::ManagementNotice::New(); notice->text = GetManagementNoticeText(); - notice->bitmap_data_url = - GURL(webui::GetBitmapDataUrl(GetManagementNoticeIconBitmap())); - notice->is_custom_logo = - policy::ManagementServiceFactory::GetForProfile(profile_) - ->GetManagementIconForBrowser() != nullptr; + + SkBitmap bitmap = GetManagementNoticeIconBitmap(); + if (!bitmap.empty()) { + notice->custom_bitmap_data_url = GURL(webui::GetBitmapDataUrl(bitmap)); + } + document_->SetManagementNotice(std::move(notice)); } @@ -195,11 +196,7 @@ return custom_icon->AsBitmap(); } - const gfx::ImageSkia default_management_icon = - gfx::CreateVectorIcon(gfx::IconDescription( - vector_icons::kBusinessIcon, 20, - web_contents_->GetColorProvider().GetColor(kColorNewTabFooterText))); - return default_management_icon.GetRepresentation(1.0f).GetBitmap(); + return SkBitmap(); } void NewTabFooterHandler::OnExtensionReady(
diff --git a/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler_unittest.cc b/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler_unittest.cc index 305aab15..2de423e5 100644 --- a/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler_unittest.cc +++ b/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler_unittest.cc
@@ -480,9 +480,8 @@ .WillOnce([](new_tab_footer::mojom::ManagementNoticePtr notice) { EXPECT_EQ("Managed by your organization", notice->text); // We only test the base URL as the data is very long and not readable. - EXPECT_TRUE(base::StartsWith(notice->bitmap_data_url.spec(), + EXPECT_TRUE(base::StartsWith(notice->custom_bitmap_data_url->spec(), "data:image/png;base64,")); - EXPECT_TRUE(notice->is_custom_logo); }); handler().UpdateManagementNotice(); @@ -496,20 +495,11 @@ policy::ManagementServiceFactory::GetForProfile(profile()), policy::EnterpriseManagementAuthority::DOMAIN_LOCAL); - const gfx::ImageSkia default_logo = - gfx::CreateVectorIcon(gfx::IconDescription( - vector_icons::kBusinessIcon, 20, - web_contents_->GetColorProvider().GetColor(kColorNewTabFooterText))); - EXPECT_TRUE(gfx::test::AreBitmapsEqual( - default_logo.GetRepresentation(1.0f).GetBitmap(), - handler_->GetManagementNoticeIconBitmap())); EXPECT_CALL(document_, SetManagementNotice) .WillOnce([](new_tab_footer::mojom::ManagementNoticePtr notice) { EXPECT_EQ("Managed by your organization", notice->text); // We only test the base URL as the data is very long and not readable. - EXPECT_TRUE(base::StartsWith(notice->bitmap_data_url.spec(), - "data:image/png;base64,")); - EXPECT_FALSE(notice->is_custom_logo); + EXPECT_FALSE(notice->custom_bitmap_data_url); }); handler().UpdateManagementNotice(); @@ -643,14 +633,13 @@ handler_->OnEnterpriseLogoUpdatedForBrowser(); - // Verify that the icon is set and recognized as a custom icon. + // Verify that the custom icon is set. document_.FlushForTesting(); testing::Mock::VerifyAndClearExpectations(&document_); EXPECT_EQ("Managed by your organization", updated_notice->text); // We only test the base URL as the data is very long and not readable. - EXPECT_TRUE(base::StartsWith(updated_notice->bitmap_data_url.spec(), + EXPECT_TRUE(base::StartsWith(updated_notice->custom_bitmap_data_url->spec(), "data:image/png;base64,")); - EXPECT_TRUE(updated_notice->is_custom_logo); // Trigger a logo change to unset the custom logo. EXPECT_CALL(document_, SetManagementNotice) @@ -663,14 +652,12 @@ handler_->OnEnterpriseLogoUpdatedForBrowser(); - // Verify that there is still a loge (default), and it is not a custom one. + // Verify that there is no longer a custom icon sent. document_.FlushForTesting(); testing::Mock::VerifyAndClearExpectations(&document_); EXPECT_EQ("Managed by your organization", updated_notice->text); // We only test the base URL as the data is very long and not readable. - EXPECT_TRUE(base::StartsWith(updated_notice->bitmap_data_url.spec(), - "data:image/png;base64,")); - EXPECT_FALSE(updated_notice->is_custom_logo); + EXPECT_FALSE(updated_notice->custom_bitmap_data_url); } TEST_F(NewTabFooterHandlerEnterpriseTest, SetCustomBackground_None) {
diff --git a/chrome/browser/ui/webui/settings/protocol_handlers_handler.cc b/chrome/browser/ui/webui/settings/protocol_handlers_handler.cc index c310209..ebc3d22 100644 --- a/chrome/browser/ui/webui/settings/protocol_handlers_handler.cc +++ b/chrome/browser/ui/webui/settings/protocol_handlers_handler.cc
@@ -134,7 +134,8 @@ UpdateHandlerList(); } -void ProtocolHandlersHandler::OnWebAppProtocolSettingsChanged() { +void ProtocolHandlersHandler::OnWebAppProtocolSettingsChanged( + const webapps::AppId& app_id) { UpdateAllAllowedLaunchProtocols(); UpdateAllDisallowedLaunchProtocols(); } @@ -146,7 +147,7 @@ void ProtocolHandlersHandler::OnWebAppUninstalled( const webapps::AppId& app_id, webapps::WebappUninstallSource uninstall_source) { - OnWebAppProtocolSettingsChanged(); + OnWebAppProtocolSettingsChanged(app_id); } void ProtocolHandlersHandler::OnWebAppInstallManagerDestroyed() {
diff --git a/chrome/browser/ui/webui/settings/protocol_handlers_handler.h b/chrome/browser/ui/webui/settings/protocol_handlers_handler.h index 69b447a..66dc7484 100644 --- a/chrome/browser/ui/webui/settings/protocol_handlers_handler.h +++ b/chrome/browser/ui/webui/settings/protocol_handlers_handler.h
@@ -57,7 +57,7 @@ void OnWebAppInstallManagerDestroyed() override; // web_app::WebAppRegistrarObserver: - void OnWebAppProtocolSettingsChanged() override; + void OnWebAppProtocolSettingsChanged(const webapps::AppId& app_id) override; void OnAppRegistrarDestroyed() override; private:
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc index 41b310a..dcc8088da 100644 --- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -754,12 +754,18 @@ {"glicLocationToggle", IDS_SETTINGS_GLIC_PERMISSIONS_LOCATION_TOGGLE}, {"glicLocationToggleSublabel", IDS_SETTINGS_GLIC_PERMISSIONS_LOCATION_TOGGLE_SUBLABEL}, + {"glicLocationToggleSublabelDataProtected", + IDS_SETTINGS_GLIC_PERMISSIONS_LOCATION_TOGGLE_SUBLABEL_DATA_PROTECTED}, {"glicMicrophoneToggle", IDS_SETTINGS_GLIC_PERMISSIONS_MICROPHONE_TOGGLE}, {"glicMicrophoneToggleSublabel", IDS_SETTINGS_GLIC_PERMISSIONS_MICROPHONE_TOGGLE_SUBLABEL}, + {"glicMicrophoneToggleSublabelDataProtected", + IDS_SETTINGS_GLIC_PERMISSIONS_MICROPHONE_TOGGLE_SUBLABEL_DATA_PROTECTED}, {"glicTabAccessToggle", IDS_SETTINGS_GLIC_PERMISSIONS_TAB_ACCESS_TOGGLE}, {"glicTabAccessToggleSublabel", IDS_SETTINGS_GLIC_PERMISSIONS_TAB_ACCESS_TOGGLE_SUBLABEL}, + {"glicTabAccessToggleSublabelDataProtected", + IDS_SETTINGS_GLIC_PERMISSIONS_TAB_ACCESS_TOGGLE_SUBLABEL_DATA_PROTECTED}, {"glicActivityButton", IDS_SETTINGS_GLIC_PERMISSIONS_ACTIVITY_BUTTON}, {"glicActivityButtonSublabel", IDS_SETTINGS_GLIC_PERMISSIONS_ACTIVITY_BUTTON_SUBLABEL}, @@ -791,11 +797,17 @@ features::kGlicLocationToggleLearnMoreURL.Get()); html_source->AddString("glicTabAccessToggleLearnMoreUrl", features::kGlicTabAccessToggleLearnMoreURL.Get()); + html_source->AddString( + "glicTabAccessToggleLearnMoreUrlDataProtected", + features::kGlicTabAccessToggleLearnMoreURLDataProtected.Get()); html_source->AddString("glicSettingsPageLearnMoreUrl", features::kGlicSettingsPageLearnMoreURL.Get()); html_source->AddBoolean( "glicClosedCaptionsFeatureEnabled", base::FeatureList::IsEnabled(features::kGlicClosedCaptioning)); + html_source->AddBoolean( + "glicUserStatusCheckFeatureEnabled", + base::FeatureList::IsEnabled(features::kGlicUserStatusCheck)); } #endif // BUILDFLAG(ENABLE_GLIC)
diff --git a/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc b/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc index 082eb34..34b344d2 100644 --- a/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc +++ b/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc
@@ -414,7 +414,7 @@ } apps::IntentFilters CreateIntentFiltersFromProtocolHandlers( - const std::vector<apps::ProtocolHandlerInfo>& protocol_handlers) { + const std::vector<custom_handlers::ProtocolHandler>& protocol_handlers) { apps::IntentFilters filters; for (const auto& handler : protocol_handlers) { auto intent_filter = std::make_unique<apps::IntentFilter>(); @@ -422,7 +422,7 @@ apps_util::kIntentActionView, apps::PatternMatchType::kLiteral); intent_filter->AddSingleValueCondition(apps::ConditionType::kScheme, - handler.protocol, + handler.protocol(), apps::PatternMatchType::kLiteral); filters.push_back(std::move(intent_filter)); } @@ -662,8 +662,12 @@ CreateShareIntentFiltersFromShareTarget(*app.share_target())); } - base::Extend(filters, CreateIntentFiltersFromProtocolHandlers( - app.protocol_handlers())); + // Includes all protocol handlers except for the ones that the user has + // explicitly disallowed. + const std::vector<custom_handlers::ProtocolHandler> protocol_handlers = + provider.os_integration_manager().GetAppProtocolHandlers(app.app_id()); + base::Extend(filters, + CreateIntentFiltersFromProtocolHandlers(protocol_handlers)); const apps::FileHandlers* enabled_file_handlers = provider.os_integration_manager().GetEnabledFileHandlers(app.app_id()); @@ -1329,6 +1333,14 @@ return is_shutting_down_; } +void WebAppPublisherHelper::OnWebAppProtocolSettingsChanged( + const webapps::AppId& app_id) { + const WebApp* web_app = GetWebApp(app_id); + if (web_app) { + delegate_->PublishWebApp(CreateWebApp(web_app)); + } +} + void WebAppPublisherHelper::OnWebAppFileHandlerApprovalStateChanged( const webapps::AppId& app_id) { const WebApp* web_app = GetWebApp(app_id);
diff --git a/chrome/browser/web_applications/app_service/web_app_publisher_helper.h b/chrome/browser/web_applications/app_service/web_app_publisher_helper.h index 9637fb09..c59d8bb8 100644 --- a/chrome/browser/web_applications/app_service/web_app_publisher_helper.h +++ b/chrome/browser/web_applications/app_service/web_app_publisher_helper.h
@@ -311,6 +311,7 @@ // WebAppRegistrarObserver: void OnAppRegistrarDestroyed() override; + void OnWebAppProtocolSettingsChanged(const webapps::AppId& app_id) override; void OnWebAppFileHandlerApprovalStateChanged( const webapps::AppId& app_id) override; void OnWebAppLastLaunchTimeChanged(
diff --git a/chrome/browser/web_applications/commands/update_protocol_handler_approval_command.cc b/chrome/browser/web_applications/commands/update_protocol_handler_approval_command.cc index b1b762c..3320d12 100644 --- a/chrome/browser/web_applications/commands/update_protocol_handler_approval_command.cc +++ b/chrome/browser/web_applications/commands/update_protocol_handler_approval_command.cc
@@ -98,7 +98,7 @@ } // Notify observers that the list of allowed or disallowed protocols was // updated. - lock_->registrar().NotifyWebAppProtocolSettingsChanged(); + lock_->registrar().NotifyWebAppProtocolSettingsChanged(app_id_); os_integration_manager.Synchronize( app_id_,
diff --git a/chrome/browser/web_applications/commands/web_install_from_url_command_browsertest.cc b/chrome/browser/web_applications/commands/web_install_from_url_command_browsertest.cc index 3b7d5361..350463c8 100644 --- a/chrome/browser/web_applications/commands/web_install_from_url_command_browsertest.cc +++ b/chrome/browser/web_applications/commands/web_install_from_url_command_browsertest.cc
@@ -13,17 +13,24 @@ #include "base/test/test_future.h" #include "base/threading/thread_restrictions.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h" #include "chrome/browser/ui/web_applications/web_app_browsertest_base.h" #include "chrome/browser/ui/web_applications/web_app_dialogs.h" #include "chrome/browser/web_applications/test/command_metrics_test_helper.h" +#include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/browser/web_applications/test/web_app_test_utils.h" #include "chrome/browser/web_applications/web_app_command_manager.h" +#include "chrome/browser/web_applications/web_app_helpers.h" +#include "chrome/browser/web_applications/web_app_install_info.h" #include "chrome/browser/web_applications/web_app_provider.h" +#include "chrome/browser/web_applications/web_app_registrar.h" #include "chrome/common/chrome_paths.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "components/permissions/permission_request_manager.h" +#include "components/services/app_service/public/cpp/app_launch_util.h" #include "components/url_formatter/elide_url.h" #include "components/webapps/browser/install_result_code.h" #include "content/public/browser/web_contents.h" @@ -42,8 +49,9 @@ #include "ui/views/controls/image_view.h" #include "ui/views/controls/label.h" #include "ui/views/interaction/element_tracker_views.h" +#include "ui/views/test/dialog_test.h" +#include "ui/views/test/widget_test.h" #include "ui/views/widget/any_widget_observer.h" - namespace { constexpr webapps::WebappInstallSource kInstallSource = webapps::WebappInstallSource::WEB_INSTALL; @@ -81,14 +89,16 @@ } // When the permission prompt shows, it must be granted or denied. - void SetPermissionResponse(bool permission_granted) { + void SetPermissionResponse(bool permission_granted, + content::WebContents* contents = nullptr) { permissions::PermissionRequestManager::AutoResponseType response = permission_granted ? permissions::PermissionRequestManager::AutoResponseType:: ACCEPT_ALL : permissions::PermissionRequestManager::AutoResponseType::DENY_ALL; - permissions::PermissionRequestManager::FromWebContents(web_contents()) + permissions::PermissionRequestManager::FromWebContents( + contents ? contents : web_contents()) ->set_auto_response_for_test(response); } @@ -105,7 +115,8 @@ } // 1 param navigator.install(install_url) - bool TryInstallApp(std::string install_url) { + bool TryInstallApp(std::string install_url, + content::WebContents* contents = nullptr) { std::string script = "navigator.install('" + install_url + "').then(result => {" " webInstallResult = result;" @@ -113,23 +124,24 @@ " webInstallError = error;" "});"; - return ExecJs(web_contents(), script); + return ExecJs(contents ? contents : web_contents(), script); } - bool ResultExists() { + bool ResultExists(content::WebContents* contents = nullptr) { // ExecJs returns false when an error is thrown, including when a variable // is undefined. - return ExecJs(web_contents(), "webInstallResult"); + return ExecJs(contents ? contents : web_contents(), "webInstallResult"); } - bool ErrorExists() { + bool ErrorExists(content::WebContents* contents = nullptr) { // ExecJs returns false when an error is thrown, including when a variable // is undefined. - return ExecJs(web_contents(), "webInstallError"); + return ExecJs(contents ? contents : web_contents(), "webInstallError"); } - std::string GetManifestIdResult() { - return EvalJs(web_contents(), "webInstallResult.manifestId") + std::string GetManifestIdResult(content::WebContents* contents = nullptr) { + return EvalJs(contents ? contents : web_contents(), + "webInstallResult.manifestId") .ExtractString(); } @@ -340,6 +352,281 @@ EXPECT_EQ(GetErrorName(), kAbortError); } +using WebInstallBackgroundAppAlreadyInstalledBrowserTest = + WebInstallFromUrlCommandBrowserTest; + +IN_PROC_BROWSER_TEST_F(WebInstallBackgroundAppAlreadyInstalledBrowserTest, + UserAcceptsLaunchDialog) { + NavigateToValidUrl(); + base::HistogramTester histograms; + + // Install a background document. + const GURL background_doc_install_url = + https_server()->GetURL("/banners/manifest_with_id_test_page.html"); + const std::string manifest_id = + GenerateManifestId("some_id", background_doc_install_url).spec(); + + webapps::AppId app_id = web_app::InstallWebAppFromPageAndCloseAppBrowser( + browser(), background_doc_install_url); + // Verify that the app was installed and launched. + histograms.ExpectBucketCount("WebApp.LaunchSource", + apps::LaunchSource::kFromReparenting, 1); + + // Initiate another install request for the same background document. + base::AutoReset<bool> auto_accept = + SetAutoAcceptWebInstallLaunchDialogForTesting(); + // Because we didn't install via web install, we'll be prompted to allow + // permission before the launch. + SetPermissionResponse(/*permission_granted=*/true); + ASSERT_TRUE(TryInstallApp(background_doc_install_url.spec())); + EXPECT_TRUE(ResultExists()); + EXPECT_FALSE(ErrorExists()); + EXPECT_EQ(GetManifestIdResult(), manifest_id); + histograms.ExpectBucketCount("WebApp.LaunchSource", + apps::LaunchSource::kFromWebInstallApi, 1); +} + +IN_PROC_BROWSER_TEST_F(WebInstallBackgroundAppAlreadyInstalledBrowserTest, + UserCancelsLaunchDialog) { + NavigateToValidUrl(); + base::HistogramTester histograms; + + // Install a background document. + const GURL background_doc_install_url = + https_server()->GetURL("/banners/manifest_with_id_test_page.html"); + const std::string manifest_id = + GenerateManifestId("some_id", background_doc_install_url).spec(); + + webapps::AppId app_id = web_app::InstallWebAppFromPageAndCloseAppBrowser( + browser(), background_doc_install_url); + // Verify that the app was installed and launched. + histograms.ExpectBucketCount("WebApp.LaunchSource", + apps::LaunchSource::kFromReparenting, 1); + + // Because we didn't install via web install, we'll be prompted to allow + // permission before the launch. + SetPermissionResponse(/*permission_granted=*/true); + views::NamedWidgetShownWaiter widget_waiter( + views::test::AnyWidgetTestPasskey{}, "WebInstallLaunchDialog"); + + // Trigger the launch dialog by initiating another install request for the + // same background document. + ExecuteScriptAsync(web_contents(), "navigator.install('" + + background_doc_install_url.spec() + + "').then(result => {" + " webInstallResult = result;" + "}).catch(error => {" + " webInstallError = error;" + "});"); + + // Wait for the launch dialog to show. + views::Widget* widget = widget_waiter.WaitIfNeededAndGet(); + ASSERT_NE(widget, nullptr); + views::test::WidgetDestroyedWaiter destroyed(widget); + // Simulate the user clicking the cancel button. + views::test::CancelDialog(widget); + destroyed.Wait(); + + // Even though the app is installed, because the user did not accept the + // launch dialog, we should not have a result to prevent fingerprinting + // concerns. + EXPECT_FALSE(ResultExists()); + EXPECT_TRUE(ErrorExists()); + histograms.ExpectBucketCount("WebApp.LaunchSource", + apps::LaunchSource::kFromWebInstallApi, 0); +} + +IN_PROC_BROWSER_TEST_F(WebInstallBackgroundAppAlreadyInstalledBrowserTest, + LaunchDialogClosesOnTabSwitch) { + NavigateToValidUrl(); + base::HistogramTester histograms; + + // Install a background document. + const GURL background_doc_install_url = + https_server()->GetURL("/banners/manifest_with_id_test_page.html"); + const std::string manifest_id = + GenerateManifestId("some_id", background_doc_install_url).spec(); + + webapps::AppId app_id = web_app::InstallWebAppFromPageAndCloseAppBrowser( + browser(), background_doc_install_url); + // Verify that the app was installed and launched. + histograms.ExpectBucketCount("WebApp.LaunchSource", + apps::LaunchSource::kFromReparenting, 1); + + // Because we didn't install via web install, we'll be prompted to allow + // permission before the launch. + SetPermissionResponse(/*permission_granted=*/true); + views::NamedWidgetShownWaiter widget_waiter( + views::test::AnyWidgetTestPasskey{}, "WebInstallLaunchDialog"); + + // Trigger the launch dialog by initiating another install request for the + // same background document. + ExecuteScriptAsync(web_contents(), "navigator.install('" + + background_doc_install_url.spec() + + "').then(result => {" + " webInstallResult = result;" + "}).catch(error => {" + " webInstallError = error;" + "});"); + + // Wait for the launch dialog to show. + views::Widget* widget = widget_waiter.WaitIfNeededAndGet(); + ASSERT_NE(widget, nullptr); + views::test::WidgetDestroyedWaiter destroyed(widget); + + // Switch to a different tab, which should dismiss the dialog. + chrome::NewTab(browser()); + + destroyed.Wait(); + + // Switch back to the tab with the app to validate JS results. + chrome::SelectPreviousTab(browser()); + EXPECT_FALSE(ResultExists()); + EXPECT_TRUE(ErrorExists()); + EXPECT_EQ(GetErrorName(), kAbortError); + + histograms.ExpectBucketCount("WebApp.LaunchSource", + apps::LaunchSource::kFromWebInstallApi, 0); +} + +IN_PROC_BROWSER_TEST_F(WebInstallBackgroundAppAlreadyInstalledBrowserTest, + UserAcceptsLaunchDialogWithinPWAWindow) { + NavigateToValidUrl(); + base::HistogramTester histograms; + + // Prepare to install an app. + const GURL install_url = + https_server()->GetURL("/banners/manifest_with_id_test_page.html"); + const std::string manifest_id = + GenerateManifestId("some_id", install_url).spec(); + auto auto_accept_pwa_install_confirmation = + SetAutoAcceptPWAInstallConfirmationForTesting(); + ui_test_utils::BrowserChangeObserver wait_for_web_app( + nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded); + + webapps::AppId app_id = + web_app::InstallWebAppFromPage(browser(), install_url); + Browser* app_browser = wait_for_web_app.Wait(); + content::WebContents* app_web_contents = + app_browser->tab_strip_model()->GetActiveWebContents(); + histograms.ExpectBucketCount("WebApp.LaunchSource", + apps::LaunchSource::kFromReparenting, 1); + + // Initiate another install request for the same background document. + base::AutoReset<bool> auto_accept = + SetAutoAcceptWebInstallLaunchDialogForTesting(); + // Because we didn't install via web install, we'll be prompted to allow + // permission before the launch. + SetPermissionResponse(/*permission_granted=*/true, app_web_contents); + + // Navigate the PWA window to a valid URL and initiate the install. + ASSERT_TRUE(ui_test_utils::NavigateToURL( + app_browser, https_server()->GetURL("/simple.html"))); + ASSERT_TRUE(TryInstallApp(install_url.spec(), app_web_contents)); + EXPECT_TRUE(ResultExists(app_web_contents)); + EXPECT_FALSE(ErrorExists(app_web_contents)); + EXPECT_EQ(GetManifestIdResult(app_web_contents), manifest_id); + histograms.ExpectBucketCount("WebApp.LaunchSource", + apps::LaunchSource::kFromWebInstallApi, 1); +} + +IN_PROC_BROWSER_TEST_F(WebInstallBackgroundAppAlreadyInstalledBrowserTest, + LaunchApp_WithoutOSIntegration_WithId) { + const GURL install_url = + https_server()->GetURL("/banners/manifest_with_id_test_page.html"); + const GURL manifest_url = + https_server()->GetURL("/banners/manifest_with_id.json"); + const GURL manifest_id = GenerateManifestId("some_id", install_url); + auto info_result = + WebAppInstallInfo::Create(manifest_url, manifest_id, install_url); + ASSERT_TRUE(info_result.has_value()); + std::unique_ptr<WebAppInstallInfo> info = + std::make_unique<WebAppInstallInfo>(std::move(info_result.value())); + info->title = u"Test App"; + info->user_display_mode = mojom::UserDisplayMode::kStandalone; + + webapps::AppId app_id = test::InstallWebAppWithoutOsIntegration( + profile(), std::move(info), + /*overwrite_existing_manifest_fields=*/false, + webapps::WebappInstallSource::EXTERNAL_DEFAULT); + + // Verify that the app has no OS integration. + web_app::WebAppProvider* provider = WebAppProvider::GetForTest(profile()); + ASSERT_TRUE(provider); + web_app::WebAppRegistrar& registrar = provider->registrar_unsafe(); + EXPECT_NE(registrar.GetAppById(app_id)->install_state(), + proto::InstallState::INSTALLED_WITH_OS_INTEGRATION); + + // Prepare to invoke navigator.install for the already installed app, which + // should initiate the launch dialog. + base::HistogramTester histograms; + base::AutoReset<bool> auto_accept = + SetAutoAcceptWebInstallLaunchDialogForTesting(); + SetPermissionResponse(/*permission_granted=*/true); + ui_test_utils::BrowserChangeObserver wait_for_web_app( + nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded); + + NavigateToValidUrl(); + ASSERT_TRUE(TryInstallApp(install_url.spec())); + + // Verify that it launched as expected. + ui_test_utils::WaitForBrowserToOpen(); + EXPECT_TRUE(ResultExists()); + EXPECT_FALSE(ErrorExists()); + EXPECT_EQ(GetManifestIdResult(), manifest_id.spec()); + histograms.ExpectBucketCount("WebApp.LaunchSource", + apps::LaunchSource::kFromWebInstallApi, 1); + // It should also now have OS integration. + EXPECT_EQ(registrar.GetAppById(app_id)->install_state(), + proto::InstallState::INSTALLED_WITH_OS_INTEGRATION); +} + +IN_PROC_BROWSER_TEST_F(WebInstallBackgroundAppAlreadyInstalledBrowserTest, + LaunchApp_WithoutOSIntegration_WithoutId) { + const GURL install_url = + https_server()->GetURL("/banners/manifest_test_page.html"); + const GURL manifest_id = GenerateManifestIdFromStartUrlOnly(install_url); + std::unique_ptr<WebAppInstallInfo> info = + WebAppInstallInfo::CreateWithStartUrlForTesting(install_url); + info->title = u"Test App"; + info->user_display_mode = mojom::UserDisplayMode::kStandalone; + + webapps::AppId app_id = test::InstallWebAppWithoutOsIntegration( + profile(), std::move(info), + /*overwrite_existing_manifest_fields=*/false, + webapps::WebappInstallSource::EXTERNAL_DEFAULT); + + // Verify that the app has no OS integration. + web_app::WebAppProvider* provider = WebAppProvider::GetForTest(profile()); + ASSERT_TRUE(provider); + web_app::WebAppRegistrar& registrar = provider->registrar_unsafe(); + EXPECT_NE(registrar.GetAppById(app_id)->install_state(), + proto::InstallState::INSTALLED_WITH_OS_INTEGRATION); + + // Prepare to invoke navigator.install for the already installed app, which + // should initiate the launch dialog. + base::HistogramTester histograms; + base::AutoReset<bool> auto_accept = + SetAutoAcceptWebInstallLaunchDialogForTesting(); + SetPermissionResponse(/*permission_granted=*/true); + ui_test_utils::BrowserChangeObserver wait_for_web_app( + nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded); + + NavigateToValidUrl(); + ASSERT_TRUE(TryInstallApp(install_url.spec())); + + // Verify that it launched as expected. + ui_test_utils::WaitForBrowserToOpen(); + EXPECT_TRUE(ResultExists()); + EXPECT_FALSE(ErrorExists()); + EXPECT_EQ(GetManifestIdResult(), manifest_id.spec()); + histograms.ExpectBucketCount("WebApp.LaunchSource", + apps::LaunchSource::kFromWebInstallApi, 1); + // It should also now have OS integration. + EXPECT_EQ(registrar.GetAppById(app_id)->install_state(), + proto::InstallState::INSTALLED_WITH_OS_INTEGRATION); +} + /////////////////////////////////////////////////////////////////////////////// // Error cases - bad manifests, invalid URLs, etc ///////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/web_applications/os_integration/os_integration_manager.cc b/chrome/browser/web_applications/os_integration/os_integration_manager.cc index c0a37abd..a00f9d0 100644 --- a/chrome/browser/web_applications/os_integration/os_integration_manager.cc +++ b/chrome/browser/web_applications/os_integration/os_integration_manager.cc
@@ -374,7 +374,8 @@ } std::vector<custom_handlers::ProtocolHandler> -OsIntegrationManager::GetAppProtocolHandlers(const webapps::AppId& app_id) { +OsIntegrationManager::GetAppProtocolHandlers( + const webapps::AppId& app_id) const { if (!protocol_handler_manager_) return std::vector<custom_handlers::ProtocolHandler>();
diff --git a/chrome/browser/web_applications/os_integration/os_integration_manager.h b/chrome/browser/web_applications/os_integration/os_integration_manager.h index f74462d..22f0e7d 100644 --- a/chrome/browser/web_applications/os_integration/os_integration_manager.h +++ b/chrome/browser/web_applications/os_integration/os_integration_manager.h
@@ -127,8 +127,8 @@ // Proxy calls for WebAppProtocolHandlerManager. virtual std::optional<GURL> TranslateProtocolUrl(const webapps::AppId& app_id, const GURL& protocol_url); - virtual std::vector<custom_handlers::ProtocolHandler> GetAppProtocolHandlers( - const webapps::AppId& app_id); + std::vector<custom_handlers::ProtocolHandler> GetAppProtocolHandlers( + const webapps::AppId& app_id) const; virtual std::vector<custom_handlers::ProtocolHandler> GetAllowedHandlersForProtocol(const std::string& protocol); virtual std::vector<custom_handlers::ProtocolHandler>
diff --git a/chrome/browser/web_applications/test/fake_web_app_ui_manager.cc b/chrome/browser/web_applications/test/fake_web_app_ui_manager.cc index 21ef43a6..09ad415 100644 --- a/chrome/browser/web_applications/test/fake_web_app_ui_manager.cc +++ b/chrome/browser/web_applications/test/fake_web_app_ui_manager.cc
@@ -218,6 +218,15 @@ NOTIMPLEMENTED(); } +void FakeWebAppUiManager::TriggerLaunchDialogForBackgroundInstall( + content::WebContents* initiating_web_contents, + const webapps::AppId& app_id, + Profile* profile, + const std::string& app_name, + base::OnceCallback<void(bool accepted)> callback) { + NOTIMPLEMENTED(); +} + void FakeWebAppUiManager::PresentUserUninstallDialog( const webapps::AppId& app_id, webapps::WebappUninstallSource uninstall_source,
diff --git a/chrome/browser/web_applications/test/fake_web_app_ui_manager.h b/chrome/browser/web_applications/test/fake_web_app_ui_manager.h index 26cbf86..bf3b4f9d 100644 --- a/chrome/browser/web_applications/test/fake_web_app_ui_manager.h +++ b/chrome/browser/web_applications/test/fake_web_app_ui_manager.h
@@ -128,6 +128,13 @@ const std::optional<GURL>& manifest_id, InstallCallback callback) override; + void TriggerLaunchDialogForBackgroundInstall( + content::WebContents* initiating_web_contents, + const webapps::AppId& app_id, + Profile* profile, + const std::string& app_name, + base::OnceCallback<void(bool accepted)> callback) override; + void PresentUserUninstallDialog( const webapps::AppId& app_id, webapps::WebappUninstallSource uninstall_source,
diff --git a/chrome/browser/web_applications/test/web_app_test_observers.cc b/chrome/browser/web_applications/test/web_app_test_observers.cc index d4311845..c872da7 100644 --- a/chrome/browser/web_applications/test/web_app_test_observers.cc +++ b/chrome/browser/web_applications/test/web_app_test_observers.cc
@@ -185,7 +185,8 @@ app_last_badging_time_changed_delegate_.Run(app_id, time); } -void WebAppTestRegistryObserverAdapter::OnWebAppProtocolSettingsChanged() { +void WebAppTestRegistryObserverAdapter::OnWebAppProtocolSettingsChanged( + const webapps::AppId& app_id) { if (app_protocol_settings_changed_delegate_) app_protocol_settings_changed_delegate_.Run(); }
diff --git a/chrome/browser/web_applications/test/web_app_test_observers.h b/chrome/browser/web_applications/test/web_app_test_observers.h index 97ef43a9..c1c129d 100644 --- a/chrome/browser/web_applications/test/web_app_test_observers.h +++ b/chrome/browser/web_applications/test/web_app_test_observers.h
@@ -132,7 +132,7 @@ const std::vector<const WebApp*>& new_apps_state) override; void OnWebAppLastBadgingTimeChanged(const webapps::AppId& app_id, const base::Time& time) override; - void OnWebAppProtocolSettingsChanged() override; + void OnWebAppProtocolSettingsChanged(const webapps::AppId& app_id) override; void OnAppRegistrarDestroyed() override; protected:
diff --git a/chrome/browser/web_applications/web_app_registrar.cc b/chrome/browser/web_applications/web_app_registrar.cc index 1dc83c4..720b862d 100644 --- a/chrome/browser/web_applications/web_app_registrar.cc +++ b/chrome/browser/web_applications/web_app_registrar.cc
@@ -330,10 +330,11 @@ observers_.RemoveObserver(observer); } -void WebAppRegistrar::NotifyWebAppProtocolSettingsChanged() { +void WebAppRegistrar::NotifyWebAppProtocolSettingsChanged( + const webapps::AppId& app_id) { DVLOG(1) << "NotifyWebAppProtocolSettingsChanged"; for (WebAppRegistrarObserver& observer : observers_) { - observer.OnWebAppProtocolSettingsChanged(); + observer.OnWebAppProtocolSettingsChanged(app_id); } }
diff --git a/chrome/browser/web_applications/web_app_registrar.h b/chrome/browser/web_applications/web_app_registrar.h index f251569..428d391 100644 --- a/chrome/browser/web_applications/web_app_registrar.h +++ b/chrome/browser/web_applications/web_app_registrar.h
@@ -522,7 +522,7 @@ void AddObserver(WebAppRegistrarObserver* observer); void RemoveObserver(WebAppRegistrarObserver* observer); - void NotifyWebAppProtocolSettingsChanged(); + void NotifyWebAppProtocolSettingsChanged(const webapps::AppId& app_id); void NotifyWebAppFileHandlerApprovalStateChanged( const webapps::AppId& app_id); void NotifyWebAppsWillBeUpdatedFromSync(
diff --git a/chrome/browser/web_applications/web_app_registrar_observer.h b/chrome/browser/web_applications/web_app_registrar_observer.h index bf5dbfb..a8573a4 100644 --- a/chrome/browser/web_applications/web_app_registrar_observer.h +++ b/chrome/browser/web_applications/web_app_registrar_observer.h
@@ -29,7 +29,7 @@ // Called after remembering the user choice to always launch an app via // a given protocol. - virtual void OnWebAppProtocolSettingsChanged() {} + virtual void OnWebAppProtocolSettingsChanged(const webapps::AppId& app_id) {} // Called after the app's access to the File Handling API has changed, e.g. by // a user selecting "always allow" in the prompt or after a policy update.
diff --git a/chrome/browser/web_applications/web_app_ui_manager.h b/chrome/browser/web_applications/web_app_ui_manager.h index ddb6674a..6b138eca 100644 --- a/chrome/browser/web_applications/web_app_ui_manager.h +++ b/chrome/browser/web_applications/web_app_ui_manager.h
@@ -276,6 +276,17 @@ const std::optional<GURL>& manifest_id, InstallCallback callback) = 0; + using WebInstallAppLaunchAcceptanceCallback = + base::OnceCallback<void(bool accepted)>; + // Triggers the web app launch dialog anchored to `initiating_web_contents` + // to launch the app given by `app_id`. Used for the Web Install API. + virtual void TriggerLaunchDialogForBackgroundInstall( + content::WebContents* initiating_web_contents, + const webapps::AppId& app_id, + Profile* profile, + const std::string& app_name, + WebInstallAppLaunchAcceptanceCallback callback) = 0; + // The uninstall dialog will be modal to |parent_window|, or a non-modal if // |parent_window| is nullptr. Use this API if a Browser window needs to be // passed in along with an UninstallCompleteCallback.
diff --git a/chrome/browser/web_applications/web_install_service_impl.cc b/chrome/browser/web_applications/web_install_service_impl.cc index 18486f81..62615eb 100644 --- a/chrome/browser/web_applications/web_install_service_impl.cc +++ b/chrome/browser/web_applications/web_install_service_impl.cc
@@ -13,6 +13,7 @@ #include "chrome/browser/web_applications/locks/app_lock.h" #include "chrome/browser/web_applications/web_app_command_manager.h" #include "chrome/browser/web_applications/web_app_command_scheduler.h" +#include "chrome/browser/web_applications/web_app_helpers.h" #include "chrome/browser/web_applications/web_app_provider.h" #include "chrome/browser/web_applications/web_app_registrar.h" #include "chrome/browser/web_applications/web_app_tab_helper.h" @@ -48,6 +49,41 @@ using PermissionStatus = blink::mojom::PermissionStatus; +// Checks if an app is installed based on `manifest_id`, if possible. Otherwise +// falls back to `install_target`. Used by the background doc install path. +// These are allowed to use unsafe registrar accesses, as this is the first step +// in a launch flow, and we later queue a command to launch, which will safely +// recheck the app's state in the registrar, and fail gracefully if it's no +// longer installed. +std::optional<webapps::AppId> IsAppInstalled( + Profile* profile, + const GURL& install_target, + const std::optional<GURL>& manifest_id) { + auto* provider = WebAppProvider::GetForWebApps(profile); + CHECK(provider); + + // TODO(crbug.com/426228062): Update WebAppFilter for background app launch. + WebAppFilter filter = WebAppFilter::InstalledInChrome(); + + // If the developer provided a manifest ID, use it to look up the app. This + // avoids issues with nested app scopes and `install_target` potentially + // launching the wrong app. + if (manifest_id) { + webapps::AppId app_id_from_manifest_id = + GenerateAppIdFromManifestId(manifest_id.value()); + + bool found_app = provider->registrar_unsafe().AppMatches( + app_id_from_manifest_id, filter); + + return found_app ? std::optional<webapps::AppId>(app_id_from_manifest_id) + : std::nullopt; + } + + // No `manifest_id` was provided. Check for the app by `install_target`. + return provider->registrar_unsafe().FindBestAppWithUrlInScope(install_target, + filter); +} + } // namespace WebInstallServiceImpl::WebInstallServiceImpl( @@ -355,30 +391,63 @@ return; } + // Now that we have permission, verify that the current web contents is not + // already involved in an install operation. This protects against showing + // multiple dialogs, either install for the current or a background document, + // or a background document launch. auto* web_contents = content::WebContents::FromRenderFrameHost(&render_frame_host()); - webapps::MLInstallabilityPromoter* promoter = webapps::MLInstallabilityPromoter::FromWebContents(web_contents); CHECK(promoter); if (promoter->HasCurrentInstall()) { // The current web contents is being installed via another method. Cancel - // this background install. + // this background install/launch flow. std::move(callback).Run(blink::mojom::WebInstallServiceResult::kAbortError, GURL()); return; } - auto* provider = WebAppProvider::GetForWebContents(web_contents); + auto* profile = + Profile::FromBrowserContext(render_frame_host().GetBrowserContext()); + auto* provider = WebAppProvider::GetForWebApps(profile); CHECK(provider); if (provider->command_manager().IsInstallingForWebContents(web_contents)) { // Another install is already scheduled on the current web contents. - // Cancel this background install. + // Cancel this background install/launch flow. std::move(callback).Run(blink::mojom::WebInstallServiceResult::kAbortError, GURL()); return; } + // Check if the background document is already installed so we can show the + // launch dialog instead of the install dialog. + std::optional<webapps::AppId> app_id = + IsAppInstalled(profile, install_target, manifest_id); + if (app_id) { + // See `IsAppInstalled` for why these are unsafe accesses. + const GURL& installed_manifest_id = + provider->registrar_unsafe().GetComputedManifestId(app_id.value()); + CHECK(installed_manifest_id != GURL()); + + // Name to display in the dialog. + std::string app_name = + provider->registrar_unsafe().GetAppShortName(app_id.value()); + // TODO(crbug.com/422940463): Show app icon in new launch dialog for + // background document launches. + + provider->ui_manager().TriggerLaunchDialogForBackgroundInstall( + web_contents, app_id.value(), profile, app_name, + base::BindOnce( + &WebInstallServiceImpl::OnBackgroundAppLaunchDialogClosed, + weak_ptr_factory_.GetWeakPtr(), std::move(callback), + installed_manifest_id)); + return; + } + + // `install_target` was not installed locally with OS integration. Proceed + // with the background install. + // Register the background install on the current web contents. std::unique_ptr<webapps::MlInstallOperationTracker> install_tracker = promoter->RegisterCurrentInstallForWebContents( @@ -390,6 +459,17 @@ weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } +void WebInstallServiceImpl::OnBackgroundAppLaunchDialogClosed( + InstallCallback callback, + const GURL& manifest_id, + bool accepted) { + // For privacy reasons, only resolve with success if the user accepted. + std::move(callback).Run( + accepted ? blink::mojom::WebInstallServiceResult::kSuccess + : blink::mojom::WebInstallServiceResult::kAbortError, + accepted ? manifest_id : GURL()); +} + void WebInstallServiceImpl::OnAppInstalled(InstallCallback callback, const webapps::AppId& app_id, webapps::InstallResultCode code) {
diff --git a/chrome/browser/web_applications/web_install_service_impl.h b/chrome/browser/web_applications/web_install_service_impl.h index fdf3e1b..5bf0d35e 100644 --- a/chrome/browser/web_applications/web_install_service_impl.h +++ b/chrome/browser/web_applications/web_install_service_impl.h
@@ -81,6 +81,11 @@ InstallCallback callback, const std::vector<blink::mojom::PermissionStatus>& permission_status); + // Used by the launch dialog to report whether the user accepted the launch. + void OnBackgroundAppLaunchDialogClosed(InstallCallback callback, + const GURL& manifest_id, + bool accepted); + // Used by web app install dialog code as the WebAppInstalledCallback. // Reports install success or failure back to Blink via `callback`. void OnAppInstalled(InstallCallback callback,
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt index e44c7dda..85ebd924 100644 --- a/chrome/build/android-arm64.pgo.txt +++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@ -chrome-android64-main-1750437161-9f0d2f2b3056cddddc34bdfaabf21ce190525094-f982c00e92433275a5cc54fbdbf93c6a67d7ca05.profdata +chrome-android64-main-1750452778-32fe86fa91e9c5be4b9dfa9dcd7bff644f46fc9a-647bf72b4d63aad24712a8bb6d3b6435a1a01ab9.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index 7972f885..5f47ca5 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1750420670-191fb31769e4c1b953b1e1f3c2e16d03c60fc2fc-c72d9ee025e53522ac3a6323bfaddf0674eb86ae.profdata +chrome-linux-main-1750442376-7a310e1a4f9c146c502fe77e012010168bebb74b-75e06514b4370138759e63b67aae06c4bdf8090c.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index fb8857f..db72272c 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1750442376-c2e7a966ba974e2fcaf07284a580e3bb5aeba341-75e06514b4370138759e63b67aae06c4bdf8090c.profdata +chrome-mac-arm-main-1750456566-167cb56c5747ba0a1a4aeaee5ef1859ec8ec0d05-d3c2953108ccedcb5c99794b670c9d4a3615b78f.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index a150315..d734a851 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1750420670-e8181a0a9082d0d1e70ac119da353f5561bd8d40-c72d9ee025e53522ac3a6323bfaddf0674eb86ae.profdata +chrome-mac-main-1750442376-92200e059d5248830aa050feec0c6f21a672798b-75e06514b4370138759e63b67aae06c4bdf8090c.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt index f27aa21..93f1bdc 100644 --- a/chrome/build/win-arm64.pgo.txt +++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@ -chrome-win-arm64-main-1750420670-ce7aa4ff53ecb5b554d76f0d5cdff9983b7d1397-c72d9ee025e53522ac3a6323bfaddf0674eb86ae.profdata +chrome-win-arm64-main-1750442376-0933c70cd60da8ac5fb8ff988a86f072e0e77acb-75e06514b4370138759e63b67aae06c4bdf8090c.profdata
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index 0d88d92..3f099695 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -500,6 +500,12 @@ &kGlicLearnMoreURLConfig, "glic-shortcuts-tab-access-toggle-learn-more-url", ""); +BASE_FEATURE_PARAM( + std::string, + kGlicTabAccessToggleLearnMoreURLDataProtected, + &kGlicLearnMoreURLConfig, + "glic-shortcuts-tab-access-toggle-learn-more-url-data-protected", + ""); BASE_FEATURE_PARAM(std::string, kGlicSettingsPageLearnMoreURL, &kGlicLearnMoreURLConfig,
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h index 843b14a..d6c7fd5 100644 --- a/chrome/common/chrome_features.h +++ b/chrome/common/chrome_features.h
@@ -277,6 +277,9 @@ extern const base::FeatureParam<std::string> kGlicLocationToggleLearnMoreURL; COMPONENT_EXPORT(CHROME_FEATURES) extern const base::FeatureParam<std::string> kGlicTabAccessToggleLearnMoreURL; +COMPONENT_EXPORT(CHROME_FEATURES) +extern const base::FeatureParam<std::string> + kGlicTabAccessToggleLearnMoreURLDataProtected; COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kGlicCSPConfig); COMPONENT_EXPORT(CHROME_FEATURES)
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index ecc131b2..58a6a424 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -5213,6 +5213,7 @@ "//ash/keyboard/ui:resources", "//chrome", "//testing/buildbot/filters:chromeos_filters", + "//third_party/liblouis:liblouis_test_data", "//ui/file_manager/integration_tests:build", ] if (use_dbus) {
diff --git a/chrome/test/data/webui/glic/api_test.ts b/chrome/test/data/webui/glic/api_test.ts index 6d145cf..6c8bfbb1 100644 --- a/chrome/test/data/webui/glic/api_test.ts +++ b/chrome/test/data/webui/glic/api_test.ts
@@ -114,15 +114,24 @@ class ApiTestFixtureBase { private clientValue?: WebClient; + private testStepLabel: string; + private testStepCount: number; // Test parameters passed to `ExecuteJsTest()`. This is undefined until // ExecuteJsTest() is called. testParams: any; - constructor(protected testStepper: TestStepper) {} + constructor(protected testStepper: TestStepper) { + this.testStepCount = 1; + this.testStepLabel = `step #${this.testStepCount} (single or first)`; + } // Return to the C++ side, and wait for it to call ContinueJsTest() to // continue execution in the JS test. Optionally, pass data to the C++ side. - advanceToNextStep(data?: any): Promise<void> { - return this.testStepper.nextStep(data); + async advanceToNextStep(data?: any): Promise<void> { + this.testStepLabel = + `in between steps ${this.testStepCount} and ${this.testStepCount + 1}`; + await this.testStepper.nextStep(data); + this.testStepCount += 1; + this.testStepLabel = `step #${this.testStepCount}`; } // Sets up the web client. This is called when the web contents loads, @@ -156,6 +165,14 @@ assertTrue(!!this.clientValue); return this.clientValue; } + + getStepLabel(): string { + return this.testStepLabel; + } + + getStepCount(): number { + return this.testStepCount; + } } // Test cases here correspond to test cases in glic_api_browsertest.cc. @@ -1203,16 +1220,20 @@ } } catch (e) { if (e instanceof Error) { - console.error(await improveStackTrace(e.stack ?? '')); + console.error( + `Test ${this.testName} failed at ${ + this.fixture!.getStepLabel()}.\n` + + await improveStackTrace(e.stack ?? '')); } - return `fail: ${e}`; + return `Failed at ${this.fixture!.getStepLabel()} due to: ${e}`; } return 'pass'; } // TestStepper implementation. nextStep(payload: any): Promise<void> { - console.info(`Waiting for next step in test ${this.testName}`); + console.info(`Waiting to continue to step #${ + this.fixture!.getStepCount() + 1} in test ${this.testName}...`); payload = payload ?? {}; // undefined is not serializable to base::Value. this.nextStepPromise.resolve({id: 'next-step', payload}); return this.continuePromise.promise; @@ -1221,7 +1242,9 @@ // Adds js source lines to the stack trace. async function improveStackTrace(stack: string) { - const outLines = []; + const outLines: string[] = []; + const contextLines = 2; // Must be >= 1 + let stackLevel = 0; for (const line of stack.split('\n')) { const m = line.match(/^\s+at.*\((.*):(\d+):(\d+)\)$/); if (m) { @@ -1230,16 +1253,28 @@ const response = await fetch(file!); const text = await response.text(); const lines = text.split('\n'); - const lineStr = lines[Number(lineNo) - 1]; - outLines.push(`${line.trim()}\n- ${lineStr}\n ${ - ' '.repeat(Number(column) - 1)}^`); + const failureLineNo = Number(lineNo) - 1; + outLines.push(`[${stackLevel}] ${line.trim()}:`); + const spacePrefixedIntroLines = + lines.slice(failureLineNo - contextLines, failureLineNo) + .map((l) => '| ' + l); + outLines.push(...spacePrefixedIntroLines); + const lineStr = lines[failureLineNo]; + outLines.push(`> ${lineStr}`); + outLines.push(`__${'_'.repeat(Number(column) - 1)}^`); + const spacePrefixedOutroLines = + lines.slice(failureLineNo + 1, failureLineNo + contextLines + 1) + .map((l) => '| ' + l); + outLines.push(...spacePrefixedOutroLines); } catch (e) { outLines.push(`${line}`); } + stackLevel += 1; } else { outLines.push(line); } } + outLines.push(''); return outLines.join('\n'); }
diff --git a/chrome/test/data/webui/new_tab_footer/app_test.ts b/chrome/test/data/webui/new_tab_footer/app_test.ts index 3b801e6..61d5743 100644 --- a/chrome/test/data/webui/new_tab_footer/app_test.ts +++ b/chrome/test/data/webui/new_tab_footer/app_test.ts
@@ -12,6 +12,7 @@ import {NewTabFooterDocumentCallbackRouter, NewTabFooterHandlerRemote, NewTabPageType} from 'chrome://newtab-footer/new_tab_footer.mojom-webui.js'; import {WindowProxy} from 'chrome://newtab-footer/window_proxy.js'; import type {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.js'; +import type {CrIconElement} from 'chrome://resources/cr_elements/cr_icon/cr_icon.js'; import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; import type {MetricsTracker} from 'chrome://webui-test/metrics_test_support.js'; import {fakeMetricsPrivate} from 'chrome://webui-test/metrics_test_support.js'; @@ -143,8 +144,8 @@ // Arrange. const managementNotice: ManagementNotice = { text: 'Managed by your organization', - bitmapDataUrl: {url: 'chrome://resources/images/chrome_logo_dark.svg'}, - isCustomLogo: false, + customBitmapDataUrl: + {url: 'chrome://resources/images/chrome_logo_dark.svg'}, }; // Act. @@ -183,8 +184,8 @@ // Arrange. const managementNoticeWithCustomLogo: ManagementNotice = { text: 'Managed by your organization', - bitmapDataUrl: {url: 'chrome://resources/images/chrome_logo_dark.svg'}, - isCustomLogo: true, + customBitmapDataUrl: + {url: 'chrome://resources/images/chrome_logo_dark.svg'}, }; // Act. @@ -195,11 +196,13 @@ let logoContainter = $$(element, '#managementNoticeLogoContainer'); assertTrue(!!logoContainter); assertTrue(logoContainter.classList.contains('custom_logo')); + const customManagementNoticeLogo = + $$<HTMLImageElement>(element, '#managementNoticeLogo'); + assertTrue(!!customManagementNoticeLogo); const managementNoticeWithDefaultLogo: ManagementNotice = { text: 'Managed by your organization', - bitmapDataUrl: {url: 'chrome://resources/images/chrome_logo_dark.svg'}, - isCustomLogo: false, + customBitmapDataUrl: null, }; // Act. @@ -209,14 +212,17 @@ logoContainter = $$(element, '#managementNoticeLogoContainer'); assertTrue(!!logoContainter); assertEquals(logoContainter.classList.length, 0); + const defaultManagementNoticeLogo = + $$<CrIconElement>(element, '#managementNoticeLogo'); + assertTrue(!!defaultManagementNoticeLogo); + assertEquals('cr:domain', defaultManagementNoticeLogo.icon); }); test('Click manageemnt notice link', async () => { // Arrange. const managementNotice: ManagementNotice = { text: 'Managed by your organization', - bitmapDataUrl: {url: 'chrome://resources/images/chrome_logo_dark.svg'}, - isCustomLogo: false, + customBitmapDataUrl: null, }; callbackRouter.setManagementNotice(managementNotice); await callbackRouter.$.flushForTesting();
diff --git a/chrome/test/data/webui/settings/appearance_page_test.ts b/chrome/test/data/webui/settings/appearance_page_test.ts index 9edb7ec..387ab139 100644 --- a/chrome/test/data/webui/settings/appearance_page_test.ts +++ b/chrome/test/data/webui/settings/appearance_page_test.ts
@@ -181,10 +181,6 @@ }, }); - appearancePage.set('pageVisibility', { - setWallpaper: true, - }); - document.body.appendChild(appearancePage); flush(); }
diff --git a/chrome/test/data/webui/settings/basic_page_test.ts b/chrome/test/data/webui/settings/basic_page_test.ts index 8de2cdb..6f3cf735 100644 --- a/chrome/test/data/webui/settings/basic_page_test.ts +++ b/chrome/test/data/webui/settings/basic_page_test.ts
@@ -13,7 +13,7 @@ import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import type {SettingsBasicPageElement, SettingsIdleLoadElement, SettingsPrefsElement, SettingsSectionElement, SyncStatus} from 'chrome://settings/settings.js'; -import {CrSettingsPrefs, MetricsBrowserProxyImpl, pageVisibility, PerformanceBrowserProxyImpl, PrivacyGuideBrowserProxyImpl, PrivacyGuideInteractions, resetRouterForTesting, Router, routes, StatusAction} from 'chrome://settings/settings.js'; +import {CrSettingsPrefs, MetricsBrowserProxyImpl, PerformanceBrowserProxyImpl, PrivacyGuideBrowserProxyImpl, PrivacyGuideInteractions, resetPageVisibilityForTesting, resetRouterForTesting, Router, routes, StatusAction} from 'chrome://settings/settings.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {eventToPromise, isChildVisible, isVisible, microtasksFinished} from 'chrome://webui-test/test_util.js'; import {flushTasks} from 'chrome://webui-test/polymer_test_util.js'; @@ -430,10 +430,9 @@ } async function createNewBasicPage() { + document.body.innerHTML = window.trustedTypes!.emptyHTML; performanceBrowserProxy = new TestPerformanceBrowserProxy(); PerformanceBrowserProxyImpl.setInstance(performanceBrowserProxy); - - document.body.innerHTML = window.trustedTypes!.emptyHTML; page = document.createElement('settings-basic-page'); document.body.appendChild(page); flush(); @@ -443,9 +442,12 @@ assertTrue(sections.length > 1); } + teardown(function() { + resetPageVisibilityForTesting(); + }); + test('performanceSectionTitlesVisible', async function() { await createNewBasicPage(); - page.pageVisibility = pageVisibility || {}; flush(); assertEquals( @@ -467,8 +469,6 @@ test('performanceVisibilityTestFeaturesAvailable', async function() { await createNewBasicPage(); - // Set the visibility of the pages under test to their default value. - page.pageVisibility = pageVisibility || {}; flush(); assertTrue( @@ -485,9 +485,8 @@ 'Speed section should exist with default page visibility'); // Set the visibility of the pages under test to "false". - page.pageVisibility = Object.assign(pageVisibility || {}, { - performance: false, - }); + resetPageVisibilityForTesting({performance: false}); + await createNewBasicPage(); flush(); assertFalse( @@ -506,7 +505,6 @@ test('performanceVisibilityTestDeviceHasBattery', async function() { await createNewBasicPage(); - page.pageVisibility = pageVisibility || {}; flush(); await performanceBrowserProxy.whenCalled('getDeviceHasBattery');
diff --git a/chrome/test/data/webui/settings/glic_page_test.ts b/chrome/test/data/webui/settings/glic_page_test.ts index 6075d156..41508d1 100644 --- a/chrome/test/data/webui/settings/glic_page_test.ts +++ b/chrome/test/data/webui/settings/glic_page_test.ts
@@ -621,4 +621,87 @@ await verifyUserAction('Glic.Settings.ClosedCaptions.Disabled'); }); }); + + suite('DataProtection_UserStatusCheckEnabled', () => { + test('DataProtectionStringsShownForEligibleUser', () => { + page.setPrefValue( + PrefName.USER_STATUS, {isEnterpriseAccountDataProtected: true}); + const locationToggle = + $<SettingsToggleButtonElement>('geolocationToggle')!; + assertEquals( + page.i18n('glicLocationToggleSublabelDataProtected'), + locationToggle.subLabel); + assertEquals('', locationToggle.learnMoreUrl); + const microphoneToggle = + $<SettingsToggleButtonElement>('microphoneToggle')!; + assertEquals( + page.i18n('glicMicrophoneToggleSublabelDataProtected'), + microphoneToggle.subLabel); + assertEquals(undefined, microphoneToggle.learnMoreUrl); + const tabAccessToggle = + $<SettingsToggleButtonElement>('tabAccessToggle')!; + assertEquals( + page.i18n('glicTabAccessToggleSublabelDataProtected'), + tabAccessToggle.subLabel); + assertEquals( + 'https://example.com/data-protection', tabAccessToggle.learnMoreUrl); + const learnMoreLabel = + $<HTMLAnchorElement>('shortcutTabAccessConsider1LearnMoreLabel')!; + assertEquals('https://example.com/data-protection', learnMoreLabel.href); + }); + + test('DataProtectionStringsNotShownForIneligibleUser', () => { + page.setPrefValue( + PrefName.USER_STATUS, {isEnterpriseAccountDataProtected: false}); + const locationToggle = + $<SettingsToggleButtonElement>('geolocationToggle')!; + assertEquals( + page.i18n('glicLocationToggleSublabel'), locationToggle.subLabel); + assertEquals( + page.i18n('glicLocationToggleLearnMoreUrl'), + locationToggle.learnMoreUrl); + const microphoneToggle = + $<SettingsToggleButtonElement>('microphoneToggle')!; + assertEquals( + page.i18n('glicMicrophoneToggleSublabel'), microphoneToggle.subLabel); + assertEquals(undefined, microphoneToggle.learnMoreUrl); + const tabAccessToggle = + $<SettingsToggleButtonElement>('tabAccessToggle')!; + assertEquals( + page.i18n('glicTabAccessToggleSublabel'), tabAccessToggle.subLabel); + assertEquals( + 'https://example.com/tab-access', tabAccessToggle.learnMoreUrl); + const learnMoreLabel = + $<HTMLAnchorElement>('shortcutTabAccessConsider1LearnMoreLabel')!; + assertEquals('https://example.com/tab-access', learnMoreLabel.href); + }); + }); + + suite('DataProtection_UserStatusCheckDisabled', () => { + test('DataProtectionStringsNotShown', () => { + page.setPrefValue( + PrefName.USER_STATUS, {isEnterpriseAccountDataProtected: true}); + const locationToggle = + $<SettingsToggleButtonElement>('geolocationToggle')!; + assertEquals( + page.i18n('glicLocationToggleSublabel'), locationToggle.subLabel); + assertEquals( + page.i18n('glicLocationToggleLearnMoreUrl'), + locationToggle.learnMoreUrl); + const microphoneToggle = + $<SettingsToggleButtonElement>('microphoneToggle')!; + assertEquals( + page.i18n('glicMicrophoneToggleSublabel'), microphoneToggle.subLabel); + assertEquals(undefined, microphoneToggle.learnMoreUrl); + const tabAccessToggle = + $<SettingsToggleButtonElement>('tabAccessToggle')!; + assertEquals( + page.i18n('glicTabAccessToggleSublabel'), tabAccessToggle.subLabel); + assertEquals( + 'https://example.com/tab-access', tabAccessToggle.learnMoreUrl); + const learnMoreLabel = + $<HTMLAnchorElement>('shortcutTabAccessConsider1LearnMoreLabel')!; + assertEquals('https://example.com/tab-access', learnMoreLabel.href); + }); + }); });
diff --git a/chrome/test/data/webui/settings/people_page_test.ts b/chrome/test/data/webui/settings/people_page_test.ts index a9618e6..64bacb2 100644 --- a/chrome/test/data/webui/settings/people_page_test.ts +++ b/chrome/test/data/webui/settings/people_page_test.ts
@@ -16,14 +16,14 @@ // </if> import {loadTimeData} from 'chrome://settings/settings.js'; - import type {SettingsPeoplePageElement} from 'chrome://settings/settings.js'; -import {pageVisibility, ProfileInfoBrowserProxyImpl, Router, routes, SignedInState, StatusAction, SyncBrowserProxyImpl} from 'chrome://settings/settings.js'; +import {ProfileInfoBrowserProxyImpl, Router, routes, SignedInState, StatusAction, SyncBrowserProxyImpl} from 'chrome://settings/settings.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; // <if expr="not is_chromeos"> import {assertLT} from 'chrome://webui-test/chai_assert.js'; import {flushTasks} from 'chrome://webui-test/polymer_test_util.js'; import {waitBeforeNextRender} from 'chrome://webui-test/polymer_test_util.js'; + // </if> import {simulateSyncStatus} from './sync_test_util.js'; @@ -59,7 +59,6 @@ document.body.innerHTML = window.trustedTypes!.emptyHTML; peoplePage = document.createElement('settings-people-page'); - peoplePage.pageVisibility = pageVisibility || {}; document.body.appendChild(peoplePage); await syncBrowserProxy.whenCalled('getSyncStatus'); @@ -111,7 +110,6 @@ document.body.innerHTML = window.trustedTypes!.emptyHTML; peoplePage = document.createElement('settings-people-page'); - peoplePage.pageVisibility = pageVisibility || {}; document.body.appendChild(peoplePage); }); @@ -151,7 +149,6 @@ document.body.innerHTML = window.trustedTypes!.emptyHTML; peoplePage = document.createElement('settings-people-page'); - peoplePage.pageVisibility = pageVisibility || {}; document.body.appendChild(peoplePage); }); @@ -431,7 +428,6 @@ document.body.innerHTML = window.trustedTypes!.emptyHTML; peoplePage = document.createElement('settings-people-page'); - peoplePage.pageVisibility = pageVisibility || {}; document.body.appendChild(peoplePage); await syncBrowserProxy.whenCalled('getSyncStatus');
diff --git a/chrome/test/data/webui/settings/people_page_test_cros.ts b/chrome/test/data/webui/settings/people_page_test_cros.ts index 629c96c5..782f785d 100644 --- a/chrome/test/data/webui/settings/people_page_test_cros.ts +++ b/chrome/test/data/webui/settings/people_page_test_cros.ts
@@ -8,7 +8,7 @@ import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import type {AccountManagerBrowserProxy, SettingsPeoplePageElement} from 'chrome://settings/settings.js'; -import {AccountManagerBrowserProxyImpl, loadTimeData, pageVisibility, ProfileInfoBrowserProxyImpl, Router, SignedInState, StatusAction, SyncBrowserProxyImpl} from 'chrome://settings/settings.js'; +import {AccountManagerBrowserProxyImpl, loadTimeData, ProfileInfoBrowserProxyImpl, Router, SignedInState, StatusAction, SyncBrowserProxyImpl} from 'chrome://settings/settings.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js'; @@ -80,7 +80,6 @@ document.body.innerHTML = window.trustedTypes!.emptyHTML; peoplePage = document.createElement('settings-people-page'); peoplePage.prefs = DEFAULT_PREFS; - peoplePage.pageVisibility = pageVisibility || {}; document.body.appendChild(peoplePage); await accountManagerBrowserProxy.whenCalled('getAccounts'); @@ -139,7 +138,6 @@ document.body.innerHTML = window.trustedTypes!.emptyHTML; peoplePage = document.createElement('settings-people-page'); peoplePage.prefs = DEFAULT_PREFS; - peoplePage.pageVisibility = pageVisibility || {}; document.body.appendChild(peoplePage); await syncBrowserProxy.whenCalled('getSyncStatus');
diff --git a/chrome/test/data/webui/settings/personalization_options_test.ts b/chrome/test/data/webui/settings/personalization_options_test.ts index 36e7908..b72deb73 100644 --- a/chrome/test/data/webui/settings/personalization_options_test.ts +++ b/chrome/test/data/webui/settings/personalization_options_test.ts
@@ -7,8 +7,8 @@ import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import type {SettingsPersonalizationOptionsElement} from 'chrome://settings/lazy_load.js'; -import type {PrivacyPageVisibility, SettingsPrefsElement} from 'chrome://settings/settings.js'; -import {CrSettingsPrefs, loadTimeData, PrivacyPageBrowserProxyImpl, SignedInState, StatusAction, SyncBrowserProxyImpl} from 'chrome://settings/settings.js'; +import type {SettingsPrefsElement} from 'chrome://settings/settings.js'; +import {CrSettingsPrefs, loadTimeData, PrivacyPageBrowserProxyImpl, resetPageVisibilityForTesting, SignedInState, StatusAction, SyncBrowserProxyImpl} from 'chrome://settings/settings.js'; import {assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {isVisible} from 'chrome://webui-test/test_util.js'; // <if expr="_google_chrome or not is_chromeos"> @@ -19,6 +19,7 @@ import {eventToPromise} from 'chrome://webui-test/test_util.js'; import {ChromeSigninUserChoice} from 'chrome://settings/settings.js'; import {webUIListenerCallback} from 'chrome://resources/js/cr.js'; + // </if> import {TestPrivacyPageBrowserProxy} from './test_privacy_page_browser_proxy.js'; @@ -41,14 +42,11 @@ return CrSettingsPrefs.initialized; }); - function buildTestElement(customPageVisibility?: PrivacyPageVisibility) { + function buildTestElement() { document.body.innerHTML = window.trustedTypes!.emptyHTML; testElement = document.createElement('settings-personalization-options'); testElement.prefs = settingsPrefs.prefs!; testElement.set('prefs.page_content_collection.enabled.value', false); - if (customPageVisibility) { - testElement.pageVisibility = customPageVisibility; - } document.body.appendChild(testElement); flush(); } @@ -63,6 +61,7 @@ teardown(function() { testElement.remove(); + resetPageVisibilityForTesting(); }); // <if expr="not is_chromeos"> @@ -287,19 +286,25 @@ }); test('searchSuggestToggleHiddenByPageVisibility', function() { - buildTestElement({ - searchPrediction: false, - networkPrediction: false, + resetPageVisibilityForTesting({ + privacy: { + searchPrediction: false, + networkPrediction: false, + }, }); + buildTestElement(); assertFalse(isVisible( testElement.shadowRoot!.querySelector('#searchSuggestToggle'))); }); test('searchSuggestToggleShownByPageVisibility', function() { - buildTestElement({ - searchPrediction: true, - networkPrediction: false, + resetPageVisibilityForTesting({ + privacy: { + searchPrediction: true, + networkPrediction: false, + }, }); + buildTestElement(); assertTrue(isVisible( testElement.shadowRoot!.querySelector('#searchSuggestToggle'))); });
diff --git a/chrome/test/data/webui/settings/settings_browsertest.cc b/chrome/test/data/webui/settings/settings_browsertest.cc index 807b10d8..372ebea 100644 --- a/chrome/test/data/webui/settings/settings_browsertest.cc +++ b/chrome/test/data/webui/settings/settings_browsertest.cc
@@ -478,6 +478,56 @@ RunTest("settings/glic_page_test.js", "runMochaSuite('GlicPage ClosedCaptionsToggleEnabled')"); } + +class SettingsGlicPageDataProtectionTest : public SettingsBrowserTest { + public: + SettingsGlicPageDataProtectionTest() { + scoped_feature_list_.InitWithFeaturesAndParameters( + {{features::kGlicUserStatusCheck, {}}, + {features::kGlicLearnMoreURLConfig, + { + {features::kGlicTabAccessToggleLearnMoreURL.name, + "https://example.com/tab-access"}, + {features::kGlicTabAccessToggleLearnMoreURLDataProtected.name, + "https://example.com/data-protection"}, + }}}, + {}); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(SettingsGlicPageDataProtectionTest, Strings) { + RunTest("settings/glic_page_test.js", + "runMochaSuite('GlicPage DataProtection_UserStatusCheckEnabled')"); +} + +class SettingsGlicPageDataProtectionTest_UserStatusCheckDisabled + : public SettingsBrowserTest { + public: + SettingsGlicPageDataProtectionTest_UserStatusCheckDisabled() { + scoped_feature_list_.InitWithFeaturesAndParameters( + {{features::kGlicLearnMoreURLConfig, + { + {features::kGlicTabAccessToggleLearnMoreURL.name, + "https://example.com/tab-access"}, + {features::kGlicTabAccessToggleLearnMoreURLDataProtected.name, + "https://example.com/data-protection"}, + }}}, + {features::kGlicUserStatusCheck}); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +IN_PROC_BROWSER_TEST_F( + SettingsGlicPageDataProtectionTest_UserStatusCheckDisabled, + Strings) { + RunTest("settings/glic_page_test.js", + "runMochaSuite('GlicPage DataProtection_UserStatusCheckDisabled')"); +} #endif class PeoplePageSyncPageTest : public SettingsBrowserTest {
diff --git a/chrome/test/data/webui/settings/settings_main_test.ts b/chrome/test/data/webui/settings/settings_main_test.ts index 3072ed6..f7ba86b 100644 --- a/chrome/test/data/webui/settings/settings_main_test.ts +++ b/chrome/test/data/webui/settings/settings_main_test.ts
@@ -6,7 +6,7 @@ import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import type {SearchManager, SettingsIdleLoadElement, SettingsMainElement, SettingsPrefsElement} from 'chrome://settings/settings.js'; -import {CrSettingsPrefs, pageVisibility, Router, routes, SearchRequest, setSearchManagerForTesting} from 'chrome://settings/settings.js'; +import {CrSettingsPrefs, Router, routes, SearchRequest, setSearchManagerForTesting} from 'chrome://settings/settings.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js'; // clang-format on @@ -59,7 +59,6 @@ settingsMain = document.createElement('settings-main'); settingsMain.prefs = settingsPrefs.prefs!; settingsMain.toolbarSpinnerActive = false; - settingsMain.pageVisibility = pageVisibility; document.body.appendChild(settingsMain); });
diff --git a/chrome/test/data/webui/settings/settings_menu_interactive_ui_test.ts b/chrome/test/data/webui/settings/settings_menu_interactive_ui_test.ts index 50f5985..2333406 100644 --- a/chrome/test/data/webui/settings/settings_menu_interactive_ui_test.ts +++ b/chrome/test/data/webui/settings/settings_menu_interactive_ui_test.ts
@@ -3,31 +3,28 @@ // found in the LICENSE file. import type {SettingsMenuElement} from 'chrome://settings/settings.js'; -import {pageVisibility} from 'chrome://settings/settings.js'; +import {resetPageVisibilityForTesting} from 'chrome://settings/settings.js'; import {assertEquals} from 'chrome://webui-test/chai_assert.js'; suite('SettingsMenuInteractiveUITest', () => { let settingsMenu: SettingsMenuElement; - setup(() => { + function createMenu() { document.body.innerHTML = window.trustedTypes!.emptyHTML; settingsMenu = document.createElement('settings-menu'); - settingsMenu.pageVisibility = pageVisibility; document.body.appendChild(settingsMenu); - }); + } test('focusFirstItem', () => { - settingsMenu.pageVisibility = Object.assign({}, pageVisibility || {}, { - people: true, - autofill: true, - }); + createMenu(); settingsMenu.focusFirstItem(); assertEquals(settingsMenu.$.people, settingsMenu.shadowRoot!.activeElement); - settingsMenu.pageVisibility = Object.assign({}, pageVisibility || {}, { + resetPageVisibilityForTesting({ people: false, autofill: true, }); + createMenu(); settingsMenu.focusFirstItem(); assertEquals( settingsMenu.$.autofill, settingsMenu.shadowRoot!.activeElement);
diff --git a/chrome/test/data/webui/settings/settings_menu_test.ts b/chrome/test/data/webui/settings/settings_menu_test.ts index 8f1114f..2b10280 100644 --- a/chrome/test/data/webui/settings/settings_menu_test.ts +++ b/chrome/test/data/webui/settings/settings_menu_test.ts
@@ -7,7 +7,7 @@ // clang-format off import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import type {SettingsMenuElement, SettingsRoutes} from 'chrome://settings/settings.js'; -import {resetRouterForTesting, loadTimeData, MetricsBrowserProxyImpl, pageVisibility, Router} from 'chrome://settings/settings.js'; +import {resetRouterForTesting, loadTimeData, MetricsBrowserProxyImpl, resetPageVisibilityForTesting, Router} from 'chrome://settings/settings.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {isVisible, microtasksFinished} from 'chrome://webui-test/test_util.js'; import {flushTasks} from 'chrome://webui-test/polymer_test_util.js'; @@ -35,6 +35,10 @@ createSettingsMenu(); }); + teardown(function() { + resetPageVisibilityForTesting(); + }); + // Test that navigating via the paper menu always clears the current // search URL parameter. test('clearsUrlSearchParam', async () => { @@ -134,21 +138,19 @@ assertPagesHidden(false); // Set the visibility of the pages under test to "false". - settingsMenu.pageVisibility = Object.assign(pageVisibility || {}, { + resetPageVisibilityForTesting({ a11y: false, advancedSettings: false, appearance: false, defaultBrowser: false, downloads: false, languages: false, - multidevice: false, onStartup: false, people: false, reset: false, - safetyCheck: false, system: false, }); - flush(); + createSettingsMenu(); // Now, the menu items should be hidden. assertPagesHidden(true);
diff --git a/chrome/test/data/webui/settings/settings_performance_menu_test.ts b/chrome/test/data/webui/settings/settings_performance_menu_test.ts index a374c574..8364307 100644 --- a/chrome/test/data/webui/settings/settings_performance_menu_test.ts +++ b/chrome/test/data/webui/settings/settings_performance_menu_test.ts
@@ -6,7 +6,7 @@ import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import type {SettingsMenuElement} from 'chrome://settings/settings.js'; -import {pageVisibility, Router, routes} from 'chrome://settings/settings.js'; +import {resetPageVisibilityForTesting, Router, routes} from 'chrome://settings/settings.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; suite('SettingsMenuPerformance', function() { @@ -16,13 +16,20 @@ return settingsMenu.shadowRoot!.querySelector<HTMLElement>('#performance'); } - setup(function() { + function createSettingsMenu() { document.body.innerHTML = window.trustedTypes!.emptyHTML; - Router.getInstance().navigateTo(routes.PERFORMANCE, undefined); + Router.getInstance().navigateTo(routes.PERFORMANCE); settingsMenu = document.createElement('settings-menu'); - settingsMenu.pageVisibility = pageVisibility; document.body.appendChild(settingsMenu); flush(); + } + + setup(function() { + createSettingsMenu(); + }); + + teardown(function() { + resetPageVisibilityForTesting(); }); test('navigateToPerformanceSection', function() { @@ -48,8 +55,8 @@ }); test('performanceMenuItemHidden', function() { - settingsMenu.pageVisibility = - Object.assign(settingsMenu.pageVisibility || {}, {performance: false}); + resetPageVisibilityForTesting({performance: false}); + createSettingsMenu(); assertTrue( getPerformanceMenuItem()!.hidden, 'performance menu item should be hidden when pageVisibility is false');
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd index a495976a..c8476cb 100644 --- a/chromeos/chromeos_strings.grd +++ b/chromeos/chromeos_strings.grd
@@ -3797,7 +3797,7 @@ anime path overlooking the ocean with falling cherry blossom leaves </message> <message name="IDS_SEA_PEN_FREEFORM_SAMPLE_PAPAVER_RHEA_STEMS" desc="An example prompt that can be used to generate an image"> - minimal still life of a few Papaver rhea stems in a glass vase on a black background + minimal still life of a few Papaver rhea flowers in a glass vase on a black background </message> <message name="IDS_SEA_PEN_FREEFORM_SAMPLE_METEOR_SHOWER" desc="An example prompt that can be used to generate an image"> photo of a night sky with a meteor shower and a few trees in the foreground, with purple and pink hues
diff --git a/chromeos/chromeos_strings_grd/IDS_SEA_PEN_FREEFORM_SAMPLE_PAPAVER_RHEA_STEMS.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SEA_PEN_FREEFORM_SAMPLE_PAPAVER_RHEA_STEMS.png.sha1 index 2b18912..1c9a454 100644 --- a/chromeos/chromeos_strings_grd/IDS_SEA_PEN_FREEFORM_SAMPLE_PAPAVER_RHEA_STEMS.png.sha1 +++ b/chromeos/chromeos_strings_grd/IDS_SEA_PEN_FREEFORM_SAMPLE_PAPAVER_RHEA_STEMS.png.sha1
@@ -1 +1 @@ -0c2293895974fac8a7f48fe87882d6dba6a70f40 \ No newline at end of file +b5c84faa029d43d165d63df2305cb4630e41388f \ No newline at end of file
diff --git a/clank b/clank index 87688db..4730f3c 160000 --- a/clank +++ b/clank
@@ -1 +1 @@ -Subproject commit 87688db09fa1af75f935e82e11b7e21594f2c443 +Subproject commit 4730f3cb56f9907131c3de8b318b4300b39d3e3d
diff --git a/components/autofill/core/browser/data_manager/payments/test_payments_data_manager.h b/components/autofill/core/browser/data_manager/payments/test_payments_data_manager.h index 3eb255a..0e3488e 100644 --- a/components/autofill/core/browser/data_manager/payments/test_payments_data_manager.h +++ b/components/autofill/core/browser/data_manager/payments/test_payments_data_manager.h
@@ -128,6 +128,8 @@ payments_customer_data_ = std::move(customer_data); } + void ClearPaymentsCustomerData() { payments_customer_data_ = nullptr; } + void SetAccountInfoForPayments(const CoreAccountInfo& account_info) { account_info_ = account_info; }
diff --git a/components/autofill/core/browser/payments/amount_extraction_manager.cc b/components/autofill/core/browser/payments/amount_extraction_manager.cc index 0b83ee2..b496e19 100644 --- a/components/autofill/core/browser/payments/amount_extraction_manager.cc +++ b/components/autofill/core/browser/payments/amount_extraction_manager.cc
@@ -16,7 +16,6 @@ #include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/browser/foundations/autofill_driver.h" #include "components/autofill/core/browser/foundations/browser_autofill_manager.h" -#include "components/autofill/core/browser/integrators/optimization_guide/autofill_optimization_guide.h" #include "components/autofill/core/browser/metrics/payments/amount_extraction_metrics.h" #include "components/autofill/core/browser/payments/amount_extraction_heuristic_regexes.h" #include "components/autofill/core/browser/payments/bnpl_manager.h"
diff --git a/components/browser_ui/strings/android/browser_ui_strings.grd b/components/browser_ui/strings/android/browser_ui_strings.grd index 0b91007a..9d2c99f4a 100644 --- a/components/browser_ui/strings/android/browser_ui_strings.grd +++ b/components/browser_ui/strings/android/browser_ui_strings.grd
@@ -1332,6 +1332,12 @@ <message name="IDS_NTP_CUSTOMIZATION_FEED_BOTTOM_SHEET" desc="Accessibility string to announce the currently displaying bottom sheet is the feed bottom sheet."> Discover feed bottom sheet </message> + <message name="IDS_NTP_CUSTOMIZATION_TURN_ON_FEED_SETTINGS" desc="Accessibility string to announce the currently selected item is a toggle to control the visibility of the discover feed section." is_accessibility_with_no_ui="true"> + Turn on discover feed + </message> + <message name="IDS_NTP_CUSTOMIZATION_SHOW_MORE" desc="Accessibility string that describes clicking on the currently selected item will show more details about it." is_accessibility_with_no_ui="true"> + Show More + </message> <!-- Time Last Accessed strings --> <message name="IDS_TIME_LAST_ACCESSED_TODAY" desc="A subtitle explaining that a given component was last accessed today.">
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/MaterialSwitchWithText.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/MaterialSwitchWithText.java index b666873..e6af494 100644 --- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/MaterialSwitchWithText.java +++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/MaterialSwitchWithText.java
@@ -105,6 +105,17 @@ } /** + * Sets the content description for the TextView besides the material switch in this {@link + * MaterialSwitchWithText}. Use this method when the content description differs from the + * displayed text. + * + * @param contentDescriptionResId The resource id of the content description to set. + */ + public void setTextContentDescriptionResId(@StringRes int contentDescriptionResId) { + mTextView.setContentDescription(getResources().getString(contentDescriptionResId)); + } + + /** * Set the OnCheckedChangeListener for the switch. * * @see CompoundButton#setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener).
diff --git a/components/facilitated_payments/core/browser/pix_account_linking_manager.cc b/components/facilitated_payments/core/browser/pix_account_linking_manager.cc index 063621a..14bd2ed0 100644 --- a/components/facilitated_payments/core/browser/pix_account_linking_manager.cc +++ b/components/facilitated_payments/core/browser/pix_account_linking_manager.cc
@@ -30,15 +30,24 @@ } // Make a request to payments backend to check if user is eligible for pix // account linking. - client_->GetMultipleRequestFacilitatedPaymentsNetworkInterface() - ->GetDetailsForCreatePaymentInstrument( - autofill::payments::GetBillingCustomerId( - CHECK_DEREF(client_->GetPaymentsDataManager())), - base::BindOnce( - &PixAccountLinkingManager:: - OnGetDetailsForCreatePaymentInstrumentResponseReceived, - weak_ptr_factory_.GetWeakPtr()), - client_->GetPaymentsDataManager()->app_locale()); + auto billing_customer_id = autofill::payments::GetBillingCustomerId( + CHECK_DEREF(client_->GetPaymentsDataManager())); + if (billing_customer_id == 0) { + // If the user is not a payments customer and has copied a Pix code, we + // automatically assume that they are eligible for account linking. + is_eligible_for_pix_account_linking_ = true; + } else { + // The user is an existing payments customer. Make a backend call to check + // eligibility for Pix account linking. + client_->GetMultipleRequestFacilitatedPaymentsNetworkInterface() + ->GetDetailsForCreatePaymentInstrument( + billing_customer_id, + base::BindOnce( + &PixAccountLinkingManager:: + OnGetDetailsForCreatePaymentInstrumentResponseReceived, + weak_ptr_factory_.GetWeakPtr()), + client_->GetPaymentsDataManager()->app_locale()); + } // TODO(crbug.com/417330610): Move this to after the user comes back to Chrome // and GetDetailsForCreatePaymentInstrument is completed. ShowPixAccountLinkingPrompt();
diff --git a/components/facilitated_payments/core/browser/pix_account_linking_manager_unittest.cc b/components/facilitated_payments/core/browser/pix_account_linking_manager_unittest.cc index 01a9ffd..ccca7d9 100644 --- a/components/facilitated_payments/core/browser/pix_account_linking_manager_unittest.cc +++ b/components/facilitated_payments/core/browser/pix_account_linking_manager_unittest.cc
@@ -8,6 +8,7 @@ #include "base/test/task_environment.h" #include "components/autofill/core/browser/data_manager/payments/test_payments_data_manager.h" +#include "components/autofill/core/browser/payments/payments_customer_data.h" #include "components/autofill/core/browser/test_utils/autofill_test_utils.h" #include "components/autofill/core/common/autofill_prefs.h" #include "components/facilitated_payments/core/browser/mock_device_delegate.h" @@ -40,6 +41,8 @@ std::make_unique<autofill::TestPaymentsDataManager>(); payments_data_manager_->SetPrefService(pref_service_.get()); payments_data_manager_->SetSyncServiceForTest(&sync_service_); + payments_data_manager_->SetPaymentsCustomerData( + std::make_unique<autofill::PaymentsCustomerData>("123456")); ON_CALL(client_, GetPaymentsDataManager) .WillByDefault(testing::Return(payments_data_manager_.get())); mock_device_delegate_ = std::make_unique<MockDeviceDelegate>(); @@ -74,13 +77,13 @@ } std::unique_ptr<PrefService> pref_service_; + std::unique_ptr<autofill::TestPaymentsDataManager> payments_data_manager_; private: // Order matters here because `manager_` keeps a reference to `client_`. MockFacilitatedPaymentsClient client_; std::unique_ptr<PixAccountLinkingManager> manager_; syncer::TestSyncService sync_service_; - std::unique_ptr<autofill::TestPaymentsDataManager> payments_data_manager_; std::unique_ptr<MockMultipleRequestFacilitatedPaymentsNetworkInterface> multiple_request_payments_network_interface_; signin::IdentityTestEnvironment identity_test_env_; @@ -167,4 +170,22 @@ EXPECT_EQ(test_api().is_eligible_for_pix_account_linking(), std::nullopt); } +TEST_F( + PixAccountLinkingManagerTest, + NoPaymentsCustomerData_GetDetailsForCreatePaymentInstrumentNotCalled_AccountLinkingEligible) { + payments_data_manager_->ClearPaymentsCustomerData(); + // Backend call for GetDetailsForPaymentInstrument should not be called if + // user is not a payments customer. + EXPECT_CALL( + *multiple_request_payments_network_interface(), + GetDetailsForCreatePaymentInstrument(testing::_, testing::_, testing::_)) + .Times(0); + + manager()->MaybeShowPixAccountLinkingPrompt(); + + // If a user is not a payments customer, they are eligible for account linking + // by default. + EXPECT_TRUE(test_api().is_eligible_for_pix_account_linking().value()); +} + } // namespace payments::facilitated
diff --git a/components/omnibox/browser/contextual_search_provider.cc b/components/omnibox/browser/contextual_search_provider.cc index 7cc2c7c..bc10c29 100644 --- a/components/omnibox/browser/contextual_search_provider.cc +++ b/components/omnibox/browser/contextual_search_provider.cc
@@ -435,6 +435,10 @@ return; match.actions.push_back(base::MakeRefCounted<T>()); }; + if (config.show_history_action) { + check_and_add.operator()<StarterPackHistoryAction>( + TemplateURLStarterPackData::StarterPackID::kHistory); + } if (config.show_bookmarks_action) { check_and_add.operator()<StarterPackBookmarksAction>( TemplateURLStarterPackData::StarterPackID::kBookmarks); @@ -443,11 +447,6 @@ check_and_add.operator()<StarterPackTabsAction>( TemplateURLStarterPackData::StarterPackID::kTabs); } - if (config.show_history_action) { - check_and_add.operator()<StarterPackHistoryAction>( - TemplateURLStarterPackData::StarterPackID::kHistory); - } - matches_.push_back(match); return true; }
diff --git a/components/omnibox/browser/featured_search_provider.cc b/components/omnibox/browser/featured_search_provider.cc index 0af440c0..fd08947 100644 --- a/components/omnibox/browser/featured_search_provider.cc +++ b/components/omnibox/browser/featured_search_provider.cc
@@ -65,11 +65,51 @@ // google" suggestions, which ranks higher than the other starter pack // suggestions. constexpr int kFeaturedEnterpriseSearchRelevance = 1470; -constexpr int kGeminiRelevance = 1460; -constexpr int kStarterPackRelevance = 1450; // IPH suggestions are grouped after all other suggestions. But they still // need to score within top N suggestions to be shown. -constexpr int kIPHRelevance = 5000; +constexpr int kIphRelevance = 5000; + +// Returns relevance for starter pack suggestions. +int StarterPackRelevance( + TemplateURLStarterPackData::StarterPackID starter_pack_id) { + // TODO(crbug.com/421415393) 1460 reserved for ai mode starter pack. + switch (starter_pack_id) { + case TemplateURLStarterPackData::StarterPackID::kGemini: + return 1459; + case TemplateURLStarterPackData::StarterPackID::kHistory: + return 1458; + case TemplateURLStarterPackData::StarterPackID::kBookmarks: + return 1457; + case TemplateURLStarterPackData::StarterPackID::kPage: + return 1456; + case TemplateURLStarterPackData::StarterPackID::kTabs: + return 1455; + case TemplateURLStarterPackData::StarterPackID::kMaxStarterPackID: + break; + } + // Can occur when syncing between different chrome versions. + return 0; +} + +// Returns description for starter pack suggestions. +std::u16string StarterPackDescription(const AutocompleteInput& input, + const TemplateURL& template_url) { + if (template_url.starter_pack_id() == TemplateURLStarterPackData::kGemini) { + return l10n_util::GetStringFUTF16(IDS_OMNIBOX_INSTANT_KEYWORD_ASK_TEXT, + template_url.keyword(), + template_url.short_name()); + } else if (template_url.short_name() == u"Tabs") { + // Very special request from UX to sentence-case "Tabs" -> "tabs" only in + // this context. It needs to stay capitalized elsewhere since it's treated + // like a proper engine name. + return l10n_util::GetStringFUTF16(IDS_OMNIBOX_INSTANT_KEYWORD_SEARCH_TEXT, + template_url.keyword(), u"tabs"); + } else { + return l10n_util::GetStringFUTF16(IDS_OMNIBOX_INSTANT_KEYWORD_SEARCH_TEXT, + template_url.keyword(), + template_url.short_name()); + } +} std::string GetIphDismissedPrefNameFor(IphType iph_type) { switch (iph_type) { @@ -231,32 +271,45 @@ void FeaturedSearchProvider::AddFeaturedKeywordMatches( const AutocompleteInput& input) { - size_t enterprise_count = 0; - if (input.GetFeaturedKeywordMode() != + // Don't add featured keywords if input doesn't start with '@'. + if (input.GetFeaturedKeywordMode() == AutocompleteInput::FeaturedKeywordMode::kFalse) { - TemplateURLService::TemplateURLVector turls; - template_url_service_->AddMatchingKeywords(input.text(), false, &turls); - for (TemplateURL* turl : turls) { - if (turl->starter_pack_id() > 0 && - turl->is_active() == TemplateURLData::ActiveStatus::kTrue) { - // Don't add the expanded set of starter pack engines unless the feature - // is enabled. - if ((turl->starter_pack_id() == TemplateURLStarterPackData::kGemini && - !OmniboxFieldTrial::IsStarterPackExpansionEnabled()) || - (turl->starter_pack_id() == TemplateURLStarterPackData::kPage && - !omnibox_feature_configs::ContextualSearch::Get() - .starter_pack_page)) { - continue; - } - AddStarterPackMatch(*turl, input); - // Don't add enterprise search aggregator engines in incognito mode. - } else if (turl->featured_by_policy() && - IsEnterpriseSearchAggregatorTemplateURLEnabled( - *turl, client_->IsOffTheRecord()) && - enterprise_count < kMaxEnterpriseSuggestions) { - AddFeaturedEnterpriseSearchMatch(*turl, input); - enterprise_count++; + return; + } + // Don't add featured keywords in realbox. + if (input.current_page_classification() == + metrics::OmniboxEventProto::NTP_REALBOX) { + return; + } + + size_t enterprise_count = 0; + TemplateURLService::TemplateURLVector turls; + template_url_service_->AddMatchingKeywords(input.text(), false, &turls); + for (TemplateURL* turl : turls) { + if (turl->starter_pack_id() > 0 && + turl->is_active() == TemplateURLData::ActiveStatus::kTrue) { + // Don't add the expanded set of starter pack engines unless the feature + // is enabled. + if ((turl->starter_pack_id() == TemplateURLStarterPackData::kGemini && + !OmniboxFieldTrial::IsStarterPackExpansionEnabled()) || + (turl->starter_pack_id() == TemplateURLStarterPackData::kPage && + !omnibox_feature_configs::ContextualSearch::Get() + .starter_pack_page)) { + continue; } + // The history starter pack engine is disabled in incognito mode. + if (client_->IsOffTheRecord() && + turl->starter_pack_id() == TemplateURLStarterPackData::kHistory) { + continue; + } + AddStarterPackMatch(*turl, input); + // Don't add enterprise search aggregator engines in incognito mode. + } else if (turl->featured_by_policy() && + IsEnterpriseSearchAggregatorTemplateURLEnabled( + *turl, client_->IsOffTheRecord()) && + enterprise_count < kMaxEnterpriseSuggestions) { + AddFeaturedEnterpriseSearchMatch(*turl, input); + enterprise_count++; } } } @@ -264,20 +317,18 @@ void FeaturedSearchProvider::AddStarterPackMatch( const TemplateURL& template_url, const AutocompleteInput& input) { - // The history starter pack engine is disabled in incognito mode. - if (client_->IsOffTheRecord() && - template_url.starter_pack_id() == TemplateURLStarterPackData::kHistory) { - return; - } - // The starter pack relevance score is currently ranked above // search-what-you-typed suggestion to avoid the keyword mode chip attaching // to the search suggestion instead of Builtin suggestions. // TODO(yoangela): This should be updated so the keyword chip only attaches to // STARTER_PACK type suggestions rather than rely on out-scoring all other // suggestions. - AutocompleteMatch match(this, kStarterPackRelevance, false, - AutocompleteMatchType::STARTER_PACK); + AutocompleteMatch match( + this, + StarterPackRelevance( + static_cast<TemplateURLStarterPackData::StarterPackID>( + template_url.starter_pack_id())), + false, AutocompleteMatchType::STARTER_PACK); const std::u16string destination_url = TemplateURLStarterPackData::GetDestinationUrlForStarterPackID( @@ -289,56 +340,14 @@ } match.destination_url = GURL(destination_url); match.transition = ui::PAGE_TRANSITION_GENERATED; - if (input.current_page_classification() != - metrics::OmniboxEventProto::NTP_REALBOX && - template_url.keyword().starts_with(u'@')) { - // The Gemini provider doesn't follow the "Search X" pattern and should - // also be ranked first. - // TODO(b/41494524): Currently templateurlservice returns the keywords in - // alphabetical order, which is the order we rank them. There should be a - // more sustainable way for specifying the order they should appear in the - // omnibox. - if (OmniboxFieldTrial::IsStarterPackExpansionEnabled() && - template_url.starter_pack_id() == TemplateURLStarterPackData::kGemini) { - match.description = l10n_util::GetStringFUTF16( - IDS_OMNIBOX_INSTANT_KEYWORD_ASK_TEXT, template_url.keyword(), - template_url.short_name()); - match.relevance = kGeminiRelevance; - } else { - std::u16string short_name = template_url.short_name(); - if (template_url.short_name() == u"Tabs") { - // Very special request from UX to sentence-case "Tabs" -> "tabs" only - // in this context. It needs to stay capitalized elsewhere since it's - // treated like a proper engine name. - match.description = short_name = u"tabs"; - } - match.description = - l10n_util::GetStringFUTF16(IDS_OMNIBOX_INSTANT_KEYWORD_SEARCH_TEXT, - template_url.keyword(), short_name); - } - match.description_class = { - {0, ACMatchClassification::NONE}, - {template_url.keyword().size(), ACMatchClassification::DIM}}; - match.contents.clear(); - match.contents_class = {{}}; - match.allowed_to_be_default_match = false; - match.keyword = template_url.keyword(); - } else { - // The Gemini provider should be ranked first. - // TODO(b/41494524): Currently templateurlservice returns the keywords in - // alphabetical order, which is the order we rank them. There should be a - // more sustainable way for specifying the order they should appear in the - // omnibox. - if (OmniboxFieldTrial::IsStarterPackExpansionEnabled() && - template_url.starter_pack_id() == TemplateURLStarterPackData::kGemini) { - match.relevance = kGeminiRelevance; - } - match.description = template_url.short_name(); - match.description_class.emplace_back(0, ACMatchClassification::NONE); - match.contents = destination_url; - match.contents_class.emplace_back(0, ACMatchClassification::URL); - match.SetAllowedToBeDefault(input); - } + match.description = StarterPackDescription(input, template_url); + match.description_class = { + {0, ACMatchClassification::NONE}, + {template_url.keyword().size(), ACMatchClassification::DIM}}; + match.contents.clear(); + match.contents_class = {{}}; + match.allowed_to_be_default_match = false; + match.keyword = template_url.keyword(); matches_.push_back(match); } @@ -379,15 +388,6 @@ void FeaturedSearchProvider::AddFeaturedEnterpriseSearchMatch( const TemplateURL& template_url, const AutocompleteInput& input) { - if (input.current_page_classification() == - metrics::OmniboxEventProto::NTP_REALBOX) { - return; - } - if (!IsEnterpriseSearchAggregatorTemplateURLEnabled( - template_url, client_->IsOffTheRecord())) { - return; - } - AutocompleteMatch match(this, kFeaturedEnterpriseSearchRelevance, false, AutocompleteMatchType::FEATURED_ENTERPRISE_SEARCH); @@ -564,7 +564,7 @@ /*matched_term=*/u"", /*iph_link_text=*/link_text, /*iph_link_url=*/GURL("chrome://settings/ai/historySearch"), - /*relevance=*/kIPHRelevance, + /*relevance=*/kIphRelevance, /*deletable=*/true); } @@ -588,7 +588,7 @@ /*matched_term=*/u"", /*iph_link_text=*/link_text, /*iph_link_url=*/GURL("chrome://settings/ai/historySearch"), - /*relevance=*/kIPHRelevance, + /*relevance=*/kIphRelevance, /*deletable=*/false); }
diff --git a/components/omnibox/browser/featured_search_provider_unittest.cc b/components/omnibox/browser/featured_search_provider_unittest.cc index 10e9c3e..ee8256ec 100644 --- a/components/omnibox/browser/featured_search_provider_unittest.cc +++ b/components/omnibox/browser/featured_search_provider_unittest.cc
@@ -6,7 +6,6 @@ #include <stddef.h> -#include <array> #include <memory> #include <string> #include <utility> @@ -51,9 +50,9 @@ const std::string kHistoryUrl = TemplateURLStarterPackData::history.destination_url; const std::string kTabsUrl = TemplateURLStarterPackData::tabs.destination_url; -const std::string kPageUrl = TemplateURLStarterPackData::page.destination_url; const std::string kGeminiUrl = TemplateURLStarterPackData::Gemini.destination_url; +const std::string kPageUrl = TemplateURLStarterPackData::page.destination_url; struct TestData { const std::u16string input; @@ -110,7 +109,7 @@ matches = provider_->matches(); ASSERT_EQ(cases[i].output.size(), matches.size()); for (size_t j = 0; j < cases[i].output.size(); ++j) { - EXPECT_EQ(GURL(cases[i].output[j]), matches[j].destination_url); + EXPECT_EQ(matches[j].destination_url, GURL(cases[i].output[j])); } } } @@ -315,15 +314,12 @@ return x.relevance > y.relevance; }); - auto expected_match_order = std::to_array<std::string>({ - kGeminiUrl, - kBookmarksUrl, - kHistoryUrl, - kPageUrl, - kTabsUrl, - }); + auto expected_match_order = std::vector<std::string>{ + kGeminiUrl, kHistoryUrl, kBookmarksUrl, kPageUrl, kTabsUrl, + }; + ASSERT_EQ(matches.size(), expected_match_order.size()); for (size_t i = 0; i < matches.size(); i++) { - EXPECT_EQ(matches[i].destination_url, GURL(expected_match_order[i])); + EXPECT_EQ(matches[i].destination_url, GURL(expected_match_order[i])) << i; } }
diff --git a/components/optimization_guide/internal b/components/optimization_guide/internal index 9e8ee51..3c89dd6 160000 --- a/components/optimization_guide/internal +++ b/components/optimization_guide/internal
@@ -1 +1 @@ -Subproject commit 9e8ee5114eb95c9675a3ea819e20773bc26e760c +Subproject commit 3c89dd68e24fda4ce1dad3c9ee0c9441059f7fb0
diff --git a/components/policy/resources/templates/policy_definitions/Miscellaneous/ChromeDataRegionSetting.yaml b/components/policy/resources/templates/policy_definitions/Miscellaneous/ChromeDataRegionSetting.yaml index ccfa3e7..e723168 100644 --- a/components/policy/resources/templates/policy_definitions/Miscellaneous/ChromeDataRegionSetting.yaml +++ b/components/policy/resources/templates/policy_definitions/Miscellaneous/ChromeDataRegionSetting.yaml
@@ -1,19 +1,20 @@ caption: Set the data regions preference for data storage desc: |- - Choose to store your covered data from <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> in a specific geographic location. + Choose to store your users' covered Chrome Enterprise data in a specific geographic location. If this policy is left unset or is set to <ph name="DATA_REGION_SETTING_NO_PREFERENCE_OPTION_NAME">No preference</ph> (value 0), covered data may be stored in any geographic location(s). If this policy is set to <ph name="DATA_REGION_SETTING_UNITED_STATES_OPTION_NAME">United States</ph> (value 1), covered data will be stored in United States. - If this policy is set to <ph name="DATA_REGION_SETTING_EUROPE_OPTION_NAME">Europe</ph> (value 2), covered data will be stored in Europe. + If this policy is set to <ph name="DATA_REGION_SETTING_EUROPE_OPTION_NAME">Europe</ph> (value 2), covered data will be stored in the European Union. + + This can only be set in the <ph name="GOOGLE_ADMIN_CONSOLE_PRODUCT_NAME">Google Admin console</ph> via Data > Compliance > Data regions > Region > Data at rest. default: 0 example_value: 0 features: cloud_only: true dynamic_refresh: false per_profile: true - unlisted: true user_only: true items: - caption: No preference.
diff --git a/components/policy/test_support/BUILD.gn b/components/policy/test_support/BUILD.gn index 50009316..3a8a461 100644 --- a/components/policy/test_support/BUILD.gn +++ b/components/policy/test_support/BUILD.gn
@@ -34,6 +34,8 @@ "request_handler_for_chrome_desktop_report.h", "request_handler_for_client_cert_provisioning.cc", "request_handler_for_client_cert_provisioning.h", + "request_handler_for_determine_promotion_eligibility.cc", + "request_handler_for_determine_promotion_eligibility.h", "request_handler_for_device_attribute_update.cc", "request_handler_for_device_attribute_update.h", "request_handler_for_device_attribute_update_permission.cc", @@ -149,6 +151,7 @@ "request_handler_for_check_user_account_unittest.cc", "request_handler_for_chrome_desktop_report_unittest.cc", "request_handler_for_client_cert_provisioning_unittest.cc", + "request_handler_for_determine_promotion_eligibility_unittest.cc", "request_handler_for_device_attribute_update_permission_unittest.cc", "request_handler_for_device_attribute_update_unittest.cc", "request_handler_for_device_initial_enrollment_state_unittest.cc",
diff --git a/components/policy/test_support/embedded_policy_test_server.cc b/components/policy/test_support/embedded_policy_test_server.cc index 9ee7b46..18ca9fbd 100644 --- a/components/policy/test_support/embedded_policy_test_server.cc +++ b/components/policy/test_support/embedded_policy_test_server.cc
@@ -24,6 +24,7 @@ #include "components/policy/test_support/request_handler_for_check_android_management.h" #include "components/policy/test_support/request_handler_for_chrome_desktop_report.h" #include "components/policy/test_support/request_handler_for_client_cert_provisioning.h" +#include "components/policy/test_support/request_handler_for_determine_promotion_eligibility.h" #include "components/policy/test_support/request_handler_for_device_attribute_update.h" #include "components/policy/test_support/request_handler_for_device_attribute_update_permission.h" #include "components/policy/test_support/request_handler_for_device_initial_enrollment_state.h" @@ -122,6 +123,8 @@ RegisterHandler( std::make_unique<RequestHandlerForClientCertProvisioning>(this)); RegisterHandler( + std::make_unique<RequestHandlerForDeterminePromotionEligibility>(this)); + RegisterHandler( std::make_unique<RequestHandlerForDeviceAttributeUpdate>(this)); RegisterHandler( std::make_unique<RequestHandlerForDeviceAttributeUpdatePermission>(this));
diff --git a/components/policy/test_support/request_handler_for_determine_promotion_eligibility.cc b/components/policy/test_support/request_handler_for_determine_promotion_eligibility.cc new file mode 100644 index 0000000..31d579df --- /dev/null +++ b/components/policy/test_support/request_handler_for_determine_promotion_eligibility.cc
@@ -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. + +#include "components/policy/test_support/request_handler_for_determine_promotion_eligibility.h" + +#include "components/policy/core/common/cloud/cloud_policy_constants.h" +#include "components/policy/proto/device_management_backend.pb.h" +#include "components/policy/test_support/test_server_helpers.h" +#include "net/base/url_util.h" +#include "net/http/http_status_code.h" +#include "net/test/embedded_test_server/http_request.h" +#include "net/test/embedded_test_server/http_response.h" + +using net::test_server::HttpRequest; +using net::test_server::HttpResponse; + +namespace em = enterprise_management; + +namespace policy { + +const char kChromeEnterpriseCoreToken[] = "CHROME_ENTERPRISE_CORE"; +const char kChromeEnterprisePremiumToken[] = "CHROME_ENTERPRISE_PREMIUM"; + +RequestHandlerForDeterminePromotionEligibility:: + RequestHandlerForDeterminePromotionEligibility( + EmbeddedPolicyTestServer* parent) + : EmbeddedPolicyTestServer::RequestHandler(parent) {} + +RequestHandlerForDeterminePromotionEligibility:: + ~RequestHandlerForDeterminePromotionEligibility() = default; + +std::string RequestHandlerForDeterminePromotionEligibility::RequestType() { + return dm_protocol::kValueRequestDeterminePromotionEligibility; +} + +std::unique_ptr<HttpResponse> +RequestHandlerForDeterminePromotionEligibility::HandleRequest( + const HttpRequest& request) { + em::DeviceManagementResponse outer_response; + em::GetUserEligiblePromotionsResponse* fake_response = + outer_response.mutable_get_user_eligible_promotions_response(); + em::PromotionEligibilityList* promotion_eligibility_list = + fake_response->mutable_promotions(); + // OAuth token will represent the promotions available for all pages, refer to + // device_management_backend.proto for source of truth + em::PromotionType promotion_type; + std::string oauth_token = + KeyValueFromUrl(request.GetURL(), dm_protocol::kParamOAuthToken); + + if (oauth_token == kChromeEnterpriseCoreToken) { + promotion_type = em::PromotionType::CHROME_ENTERPRISE_CORE; + } else if (oauth_token == kChromeEnterprisePremiumToken) { + promotion_type = em::PromotionType::CHROME_ENTERPRISE_PREMIUM; + } else { + promotion_type = em::PromotionType::PROMOTION_TYPE_UNSPECIFIED; + } + + promotion_eligibility_list->set_policy_page_promotion(promotion_type); + promotion_eligibility_list->set_management_page_promotion(promotion_type); + promotion_eligibility_list->set_interstitial_block_promotion(promotion_type); + promotion_eligibility_list->set_interstitial_warn_promotion(promotion_type); + promotion_eligibility_list->set_ntp_promotion(promotion_type); + promotion_eligibility_list->set_cws_extension_details_promotion( + promotion_type); + promotion_eligibility_list->set_cws_privacy_details_promotion(promotion_type); + + return CreateHttpResponse(net::HTTP_OK, outer_response); +} + +} // namespace policy
diff --git a/components/policy/test_support/request_handler_for_determine_promotion_eligibility.h b/components/policy/test_support/request_handler_for_determine_promotion_eligibility.h new file mode 100644 index 0000000..489839a --- /dev/null +++ b/components/policy/test_support/request_handler_for_determine_promotion_eligibility.h
@@ -0,0 +1,34 @@ +// 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_POLICY_TEST_SUPPORT_REQUEST_HANDLER_FOR_DETERMINE_PROMOTION_ELIGIBILITY_H_ +#define COMPONENTS_POLICY_TEST_SUPPORT_REQUEST_HANDLER_FOR_DETERMINE_PROMOTION_ELIGIBILITY_H_ + +#include "components/policy/test_support/embedded_policy_test_server.h" + +namespace policy { + +extern const char kChromeEnterpriseCoreToken[]; +extern const char kChromeEnterprisePremiumToken[]; + +// Handler for request type `determine_promotion_eligibility`. +class RequestHandlerForDeterminePromotionEligibility + : public EmbeddedPolicyTestServer::RequestHandler { + public: + explicit RequestHandlerForDeterminePromotionEligibility( + EmbeddedPolicyTestServer* parent); + RequestHandlerForDeterminePromotionEligibility( + RequestHandlerForDeterminePromotionEligibility&& handler) = delete; + RequestHandlerForDeterminePromotionEligibility& operator=( + RequestHandlerForDeterminePromotionEligibility&& handler) = delete; + ~RequestHandlerForDeterminePromotionEligibility() override; + + // EmbeddedPolicyTestServer::RequestHandler: + std::string RequestType() override; + std::unique_ptr<net::test_server::HttpResponse> HandleRequest( + const net::test_server::HttpRequest& request) override; +}; +} // namespace policy + +#endif // COMPONENTS_POLICY_TEST_SUPPORT_REQUEST_HANDLER_FOR_DETERMINE_PROMOTION_ELIGIBILITY_H_
diff --git a/components/policy/test_support/request_handler_for_determine_promotion_eligibility_unittest.cc b/components/policy/test_support/request_handler_for_determine_promotion_eligibility_unittest.cc new file mode 100644 index 0000000..effcfdc --- /dev/null +++ b/components/policy/test_support/request_handler_for_determine_promotion_eligibility_unittest.cc
@@ -0,0 +1,103 @@ +// 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/policy/test_support/request_handler_for_determine_promotion_eligibility.h" + +#include "base/test/protobuf_matchers.h" +#include "components/policy/core/common/cloud/cloud_policy_constants.h" +#include "components/policy/proto/device_management_backend.pb.h" +#include "components/policy/test_support/embedded_policy_test_server_test_base.h" +#include "net/http/http_status_code.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::base::test::EqualsProto; + +namespace em = enterprise_management; + +namespace { + +constexpr char kDeviceId[] = "fake_device_id"; + +} // namespace + +namespace policy { + +class RequestHandlerForDeterminePromotionEligibilityTest + : public EmbeddedPolicyTestServerTestBase { + protected: + RequestHandlerForDeterminePromotionEligibilityTest() = default; + ~RequestHandlerForDeterminePromotionEligibilityTest() override = default; + + void SetUp() override { + EmbeddedPolicyTestServerTestBase::SetUp(); + + SetRequestTypeParam( + dm_protocol::kValueRequestDeterminePromotionEligibility); + SetAppType(dm_protocol::kValueAppType); + SetDeviceIdParam(kDeviceId); + SetDeviceType(dm_protocol::kValueDeviceType); + } +}; + +em::DeviceManagementResponse CreateExpectedResponse( + em::PromotionType promotion_type) { + em::DeviceManagementResponse outer_response; + em::GetUserEligiblePromotionsResponse* fake_response = + outer_response.mutable_get_user_eligible_promotions_response(); + em::PromotionEligibilityList* promotion_eligibility_list = + fake_response->mutable_promotions(); + + // Set all promotion types to the provided promotion_type + promotion_eligibility_list->set_policy_page_promotion(promotion_type); + promotion_eligibility_list->set_management_page_promotion(promotion_type); + promotion_eligibility_list->set_interstitial_block_promotion(promotion_type); + promotion_eligibility_list->set_interstitial_warn_promotion(promotion_type); + promotion_eligibility_list->set_ntp_promotion(promotion_type); + promotion_eligibility_list->set_cws_extension_details_promotion( + promotion_type); + promotion_eligibility_list->set_cws_privacy_details_promotion(promotion_type); + + return outer_response; +} + +class RequestHandlerForDeterminePromotionEligibilityParameterizedTest + : public RequestHandlerForDeterminePromotionEligibilityTest, + public testing::WithParamInterface< + std::tuple<std::string, em::PromotionType>> { + protected: +}; + +INSTANTIATE_TEST_SUITE_P( + PromotionEligibilityTests, + RequestHandlerForDeterminePromotionEligibilityParameterizedTest, + testing::Values( + std::make_tuple("unspecified", + em::PromotionType::PROMOTION_TYPE_UNSPECIFIED), + std::make_tuple(kChromeEnterprisePremiumToken, + em::PromotionType::CHROME_ENTERPRISE_PREMIUM), + std::make_tuple(kChromeEnterpriseCoreToken, + em::PromotionType::CHROME_ENTERPRISE_CORE))); + +TEST_P(RequestHandlerForDeterminePromotionEligibilityParameterizedTest, + HandleRequest_ValidPromotionType) { + std::string oauth_token_value = std::get<0>(GetParam()); + em::PromotionType expected_promotion_type = std::get<1>(GetParam()); + + SetOAuthToken(oauth_token_value); + em::DeviceManagementRequest device_management_request; + SetPayload(device_management_request); + + em::DeviceManagementResponse outer_response = + CreateExpectedResponse(expected_promotion_type); + + StartRequestAndWait(); + + EXPECT_EQ(GetResponseCode(), net::HTTP_OK); + ASSERT_TRUE(HasResponseBody()); + auto response = GetDeviceManagementResponse(); + EXPECT_THAT(response, EqualsProto(outer_response)); +} + +} // namespace policy
diff --git a/components/safe_browsing/core/browser/safe_browsing_url_checker_impl_unittest.cc b/components/safe_browsing/core/browser/safe_browsing_url_checker_impl_unittest.cc index 8411b584..7bf4b93f 100644 --- a/components/safe_browsing/core/browser/safe_browsing_url_checker_impl_unittest.cc +++ b/components/safe_browsing/core/browser/safe_browsing_url_checker_impl_unittest.cc
@@ -49,6 +49,30 @@ return arg.threat_source == threatSource; } +class Waiter { + public: + void OnCall() { + was_called_ = true; + if (run_loop_quit_closure_) { + std::move(run_loop_quit_closure_).Run(); + } + } + + bool WasCalled() const { return was_called_; } + + void WaitForCall() { + if (!was_called_) { + base::RunLoop run_loop; + run_loop_quit_closure_ = run_loop.QuitClosure(); + run_loop.Run(); + } + } + + private: + bool was_called_ = false; + base::OnceClosure run_loop_quit_closure_; +}; + class MockSafeBrowsingDatabaseManager : public TestSafeBrowsingDatabaseManager { public: MockSafeBrowsingDatabaseManager() @@ -57,11 +81,10 @@ // SafeBrowsingDatabaseManager implementation. // Checks the threat type of |gurl| previously set by |SetThreatTypeForUrl|. // It crashes if the threat type of |gurl| is not set in advance. - bool CheckBrowseUrl( - const GURL& gurl, - const safe_browsing::SBThreatTypeSet& threat_types, - Client* client, - CheckBrowseUrlType check_type) override { + bool CheckBrowseUrl(const GURL& gurl, + const safe_browsing::SBThreatTypeSet& threat_types, + Client* client, + CheckBrowseUrlType check_type) override { std::string url = gurl.spec(); DCHECK(base::Contains(urls_threat_type_, url)); DCHECK(base::Contains(urls_delayed_callback_, url)); @@ -182,7 +205,14 @@ explicit MockUrlCheckerDelegate(SafeBrowsingDatabaseManager* database_manager) : database_manager_(database_manager), threat_types_(SBThreatTypeSet( - {safe_browsing::SBThreatType::SB_THREAT_TYPE_URL_PHISHING})) {} + {safe_browsing::SBThreatType::SB_THREAT_TYPE_URL_PHISHING})) { + ON_CALL(*this, StartDisplayingBlockingPageHelper) + .WillByDefault(::testing::Invoke( + [this](const security_interstitials::UnsafeResource&, + const std::string&, const net::HttpRequestHeaders&, bool) { + start_displaying_blocking_helper_waiter_.OnCall(); + })); + } MOCK_METHOD1(MaybeDestroyNoStatePrefetchContents, void(base::OnceCallback<content::WebContents*()>)); @@ -226,6 +256,10 @@ are_background_hprt_lookups_allowed_ = are_background_hprt_lookups_allowed; } + void WaitForStartDisplayingBlockingPageHelper() { + start_displaying_blocking_helper_waiter_.WaitForCall(); + } + protected: ~MockUrlCheckerDelegate() override = default; @@ -233,6 +267,7 @@ raw_ptr<SafeBrowsingDatabaseManager> database_manager_; SBThreatTypeSet threat_types_; bool are_background_hprt_lookups_allowed_ = true; + Waiter start_displaying_blocking_helper_waiter_; }; class FakeRealTimeUrlLookupService @@ -402,6 +437,35 @@ bool check_allowlist_before_hash_database = false; }; +// Has same API as +// base::MockCallback<SafeBrowsingUrlCheckerImpl::NativeCheckUrlCallback>, but +// exposes Wait() to wait for method to be called. +class WaitableNativeCheckUrlCallback { + public: + MOCK_METHOD4( + Run, + void(bool, bool, bool, SafeBrowsingUrlCheckerImpl::PerformedCheck)); + + void Wait() { run_loop_.Run(); } + + SafeBrowsingUrlCheckerImpl::NativeCheckUrlCallback Get() { + return base::BindOnce(&WaitableNativeCheckUrlCallback::RunInternal, + base::Unretained(this)); + } + + private: + base::RunLoop run_loop_; + + void RunInternal(bool proceed, + bool showed_interstitial, + bool has_post_commit_interstitial_skipped, + SafeBrowsingUrlCheckerImpl::PerformedCheck performed_check) { + Run(proceed, showed_interstitial, has_post_commit_interstitial_skipped, + performed_check); + run_loop_.Quit(); + } +}; + } // namespace class SafeBrowsingUrlCheckerTest : public PlatformTest { @@ -533,8 +597,7 @@ GURL url("https://example.test/"); database_manager_->SetThreatTypeForUrl(url, SBThreatType::SB_THREAT_TYPE_SAFE, /*delayed_callback=*/false); - base::MockCallback<SafeBrowsingUrlCheckerImpl::NativeCheckUrlCallback> - callback; + WaitableNativeCheckUrlCallback callback; EXPECT_CALL( callback, Run(/*proceed=*/true, /*showed_interstitial=*/false, @@ -545,7 +608,8 @@ .Times(0); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + callback.Wait(); + histogram_tester_.ExpectUniqueSample("SafeBrowsing.CheckUrl.Timeout", /*sample=*/false, /*expected_bucket_count=*/1); @@ -573,7 +637,7 @@ IsSameThreatSource(ThreatSource::UNKNOWN), _, _, _)) .Times(1); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + url_checker_delegate_->WaitForStartDisplayingBlockingPageHelper(); ValidateCheckUrlTimeTakenMetrics(/*expected_hprt_log_count=*/0, /*expected_urt_log_count=*/0, /*expected_hpd_log_count=*/1); @@ -590,8 +654,7 @@ database_manager_->SetThreatTypeForUrl(origin_url, SB_THREAT_TYPE_SAFE, /*delayed_callback=*/false); - base::MockCallback<SafeBrowsingUrlCheckerImpl::NativeCheckUrlCallback> - origin_callback; + WaitableNativeCheckUrlCallback origin_callback; EXPECT_CALL( origin_callback, Run(/*proceed=*/true, /*showed_interstitial=*/false, @@ -606,8 +669,7 @@ database_manager_->SetThreatTypeForUrl(redirect_url, SB_THREAT_TYPE_SAFE, /*delayed_callback=*/false); - base::MockCallback<SafeBrowsingUrlCheckerImpl::NativeCheckUrlCallback> - redirect_callback; + WaitableNativeCheckUrlCallback redirect_callback; EXPECT_CALL( redirect_callback, Run(/*proceed=*/true, /*showed_interstitial=*/false, @@ -616,7 +678,8 @@ safe_browsing_url_checker->CheckUrl(redirect_url, "GET", redirect_callback.Get()); - task_environment_.RunUntilIdle(); + origin_callback.Wait(); + redirect_callback.Wait(); ValidateCheckUrlTimeTakenMetrics(/*expected_hprt_log_count=*/0, /*expected_urt_log_count=*/0, /*expected_hpd_log_count=*/2); @@ -658,7 +721,8 @@ StartDisplayingBlockingPageHelper(_, _, _, _)) .Times(1); database_manager_->RestartDelayedCallback(origin_url); - task_environment_.RunUntilIdle(); + + url_checker_delegate_->WaitForStartDisplayingBlockingPageHelper(); ValidateCheckUrlTimeTakenMetrics(/*expected_hprt_log_count=*/0, /*expected_urt_log_count=*/0, /*expected_hpd_log_count=*/1); @@ -682,8 +746,7 @@ database_manager_->SetThreatTypeForUrl(url, SB_THREAT_TYPE_URL_PHISHING, /*delayed_callback=*/false); - base::MockCallback<SafeBrowsingUrlCheckerImpl::NativeCheckUrlCallback> - callback; + WaitableNativeCheckUrlCallback callback; EXPECT_CALL( callback, Run(/*proceed=*/true, /*showed_interstitial=*/false, @@ -691,7 +754,7 @@ SafeBrowsingUrlCheckerImpl::PerformedCheck::kHashDatabaseCheck)); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + callback.Wait(); ValidateCheckUrlTimeTakenMetrics(/*expected_hprt_log_count=*/0, /*expected_urt_log_count=*/0, /*expected_hpd_log_count=*/1); @@ -713,8 +776,7 @@ database_manager_->SetThreatTypeForUrl(url, SB_THREAT_TYPE_SAFE, /*delayed_callback=*/false); - base::MockCallback<SafeBrowsingUrlCheckerImpl::NativeCheckUrlCallback> - callback; + WaitableNativeCheckUrlCallback callback; EXPECT_CALL( callback, Run(/*proceed=*/true, /*showed_interstitial=*/false, @@ -722,7 +784,7 @@ SafeBrowsingUrlCheckerImpl::PerformedCheck::kHashDatabaseCheck)); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + callback.Wait(); ValidateCheckUrlTimeTakenMetrics(/*expected_hprt_log_count=*/0, /*expected_urt_log_count=*/0, /*expected_hpd_log_count=*/1); @@ -753,7 +815,7 @@ .Times(1); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + url_checker_delegate_->WaitForStartDisplayingBlockingPageHelper(); ValidateCheckUrlTimeTakenMetrics(/*expected_hprt_log_count=*/0, /*expected_urt_log_count=*/0, /*expected_hpd_log_count=*/1); @@ -787,7 +849,7 @@ .Times(1); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + url_checker_delegate_->WaitForStartDisplayingBlockingPageHelper(); ValidateCheckUrlTimeTakenMetrics(/*expected_hprt_log_count=*/0, /*expected_urt_log_count=*/0, /*expected_hpd_log_count=*/1); @@ -820,7 +882,7 @@ .Times(1); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + url_checker_delegate_->WaitForStartDisplayingBlockingPageHelper(); CheckUrlRealTimeLocalMatchMetrics( /*expected_local_match_result=*/true, /*expect_url_lookup_service_metric_suffix=*/true); @@ -848,8 +910,7 @@ url_lookup_service_->SetThreatTypeForUrl(url, SB_THREAT_TYPE_SAFE, /*should_complete_lookup=*/true); - base::MockCallback<SafeBrowsingUrlCheckerImpl::NativeCheckUrlCallback> - callback; + WaitableNativeCheckUrlCallback callback; EXPECT_CALL( callback, Run(/*proceed=*/true, /*showed_interstitial=*/false, @@ -860,7 +921,7 @@ .Times(0); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + callback.Wait(); histogram_tester_.ExpectUniqueSample("SafeBrowsing.CheckUrl.Timeout", /*sample=*/false, /*expected_bucket_count=*/1); @@ -894,8 +955,7 @@ url_lookup_service_->SetThreatTypeForUrl(url, SB_THREAT_TYPE_SAFE, /*should_complete_lookup=*/true); - base::MockCallback<SafeBrowsingUrlCheckerImpl::NativeCheckUrlCallback> - callback; + WaitableNativeCheckUrlCallback callback; EXPECT_CALL( callback, Run(/*proceed=*/true, /*showed_interstitial=*/false, @@ -906,7 +966,7 @@ .Times(0); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + callback.Wait(); histogram_tester_.ExpectUniqueSample("SafeBrowsing.CheckUrl.Timeout", /*sample=*/false, /*expected_bucket_count=*/1); @@ -937,8 +997,7 @@ /*should_complete_lookup=*/true); url_lookup_service_->SetIsCachedResponse(true); - base::MockCallback<SafeBrowsingUrlCheckerImpl::NativeCheckUrlCallback> - callback; + WaitableNativeCheckUrlCallback callback; EXPECT_CALL( callback, Run(/*proceed=*/true, /*showed_interstitial=*/false, @@ -949,7 +1008,7 @@ .Times(0); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + callback.Wait(); histogram_tester_.ExpectUniqueSample( "SafeBrowsing.RT.GetCache.FallbackThreatType", @@ -994,7 +1053,7 @@ .Times(1); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + url_checker_delegate_->WaitForStartDisplayingBlockingPageHelper(); histogram_tester_.ExpectUniqueSample( "SafeBrowsing.RT.GetCache.FallbackThreatType", @@ -1028,8 +1087,7 @@ url, /*match=*/false, /*logging_details=*/std::nullopt); - base::MockCallback<SafeBrowsingUrlCheckerImpl::NativeCheckUrlCallback> - callback; + WaitableNativeCheckUrlCallback callback; EXPECT_CALL( callback, Run(/*proceed=*/true, /*showed_interstitial=*/false, @@ -1043,7 +1101,7 @@ .Times(0); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + callback.Wait(); CheckUrlRealTimeLocalMatchMetrics( /*expected_local_match_result=*/false, /*expect_url_lookup_service_metric_suffix=*/true); @@ -1074,7 +1132,7 @@ .Times(1); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + url_checker_delegate_->WaitForStartDisplayingBlockingPageHelper(); CheckUrlRealTimeLocalMatchMetrics( /*expected_local_match_result=*/false, /*expect_url_lookup_service_metric_suffix=*/true); @@ -1112,7 +1170,7 @@ .Times(1); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + url_checker_delegate_->WaitForStartDisplayingBlockingPageHelper(); CheckUrlRealTimeLocalMatchMetrics( /*expected_local_match_result=*/false, /*expect_url_lookup_service_metric_suffix=*/true); @@ -1149,7 +1207,7 @@ .Times(1); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + url_checker_delegate_->WaitForStartDisplayingBlockingPageHelper(); CheckUrlRealTimeLocalMatchMetrics( /*expected_local_match_result=*/false, /*expect_url_lookup_service_metric_suffix=*/true); @@ -1176,8 +1234,7 @@ url_lookup_service_->SetThreatTypeForUrl(url, SB_THREAT_TYPE_SAFE, /*should_complete_lookup=*/true); - base::MockCallback<SafeBrowsingUrlCheckerImpl::NativeCheckUrlCallback> - callback; + WaitableNativeCheckUrlCallback callback; EXPECT_CALL( callback, Run(/*proceed=*/true, /*showed_interstitial=*/false, @@ -1188,7 +1245,7 @@ .Times(0); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + callback.Wait(); CheckUrlRealTimeLocalMatchMetrics( /*expected_local_match_result=*/false, /*expect_url_lookup_service_metric_suffix=*/true); @@ -1237,8 +1294,7 @@ url_lookup_service_->SetThreatTypeForUrl(redirect_url, SB_THREAT_TYPE_SAFE, /*should_complete_lookup=*/true); - base::MockCallback<SafeBrowsingUrlCheckerImpl::NativeCheckUrlCallback> - redirect_callback; + WaitableNativeCheckUrlCallback redirect_callback; EXPECT_CALL( redirect_callback, Run(/*proceed=*/true, /*showed_interstitial=*/false, @@ -1247,7 +1303,7 @@ safe_browsing_url_checker->CheckUrl(redirect_url, "GET", redirect_callback.Get()); - task_environment_.RunUntilIdle(); + redirect_callback.Wait(); ValidateCheckUrlTimeTakenMetrics(/*expected_hprt_log_count=*/0, /*expected_urt_log_count=*/2, /*expected_hpd_log_count=*/0); @@ -1322,7 +1378,7 @@ /*logging_details=*/std::nullopt); url_lookup_service_->SetThreatTypeForUrl(url, SB_THREAT_TYPE_URL_PHISHING, /*should_complete_lookup=*/false); - base::MockCallback<SafeBrowsingUrlCheckerImpl::NativeCheckUrlCallback> cb; + WaitableNativeCheckUrlCallback cb; EXPECT_CALL( cb, Run(/*proceed=*/true, /*showed_interstitial=*/false, @@ -1332,7 +1388,7 @@ EXPECT_FALSE(database_manager_->HasCalledCancelCheck()); task_environment_.FastForwardBy(base::Seconds(5)); EXPECT_FALSE(database_manager_->HasCalledCancelCheck()); - task_environment_.RunUntilIdle(); + cb.Wait(); histograms.ExpectUniqueSample("SafeBrowsing.CheckUrl.Timeout", /*sample=*/true, /*expected_bucket_count=*/1); @@ -1354,8 +1410,7 @@ database_manager_->SetThreatTypeForUrl(url, SB_THREAT_TYPE_URL_PHISHING, /*delayed_callback=*/true); - base::MockCallback<SafeBrowsingUrlCheckerImpl::NativeCheckUrlCallback> - callback; + WaitableNativeCheckUrlCallback callback; EXPECT_CALL( callback, Run(/*proceed=*/true, /*showed_interstitial=*/false, @@ -1365,7 +1420,7 @@ EXPECT_FALSE(database_manager_->HasCalledCancelCheck()); task_environment_.FastForwardBy(base::Seconds(5)); EXPECT_TRUE(database_manager_->HasCalledCancelCheck()); - task_environment_.RunUntilIdle(); + callback.Wait(); histograms.ExpectUniqueSample("SafeBrowsing.CheckUrl.Timeout", /*sample=*/true, /*expected_bucket_count=*/1); @@ -1387,8 +1442,7 @@ database_manager_->SetThreatTypeForUrl(url, SB_THREAT_TYPE_SAFE, /*delayed_callback=*/false); - base::MockCallback<SafeBrowsingUrlCheckerImpl::NativeCheckUrlCallback> - callback; + WaitableNativeCheckUrlCallback callback; EXPECT_CALL( callback, Run(/*proceed=*/true, /*showed_interstitial=*/false, @@ -1400,7 +1454,7 @@ IsSameThreatSource(ThreatSource::UNKNOWN), _, _, _)) .Times(0); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + callback.Wait(); CheckHashRealTimeMetrics(/*expected_local_match_result=*/std::nullopt, /*expected_is_service_found=*/std::nullopt, /*expected_can_check_reputation=*/false); @@ -1424,8 +1478,7 @@ url, /*match=*/true, /*logging_details=*/std::nullopt); - base::MockCallback<SafeBrowsingUrlCheckerImpl::NativeCheckUrlCallback> - callback; + WaitableNativeCheckUrlCallback callback; EXPECT_CALL( callback, Run(/*proceed=*/true, /*showed_interstitial=*/false, @@ -1437,7 +1490,7 @@ IsSameThreatSource(ThreatSource::UNKNOWN), _, _, _)) .Times(0); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + callback.Wait(); CheckHashRealTimeMetrics(/*expected_local_match_result=*/true, /*expected_is_service_found=*/std::nullopt, /*expected_can_check_reputation=*/true); @@ -1476,7 +1529,7 @@ IsSameThreatSource(ThreatSource::UNKNOWN), _, _, _)) .Times(1); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + url_checker_delegate_->WaitForStartDisplayingBlockingPageHelper(); CheckHashRealTimeMetrics(/*expected_local_match_result=*/true, /*expected_is_service_found=*/std::nullopt, /*expected_can_check_reputation=*/true); @@ -1505,8 +1558,7 @@ url, /*match=*/false, /*logging_details=*/std::nullopt); - base::MockCallback<SafeBrowsingUrlCheckerImpl::NativeCheckUrlCallback> - callback; + WaitableNativeCheckUrlCallback callback; EXPECT_CALL( callback, Run(/*proceed=*/true, /*showed_interstitial=*/false, @@ -1519,7 +1571,7 @@ IsSameThreatSource(ThreatSource::NATIVE_PVER5_REAL_TIME), _, _, _)) .Times(0); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + callback.Wait(); CheckHashRealTimeMetrics(/*expected_local_match_result=*/false, /*expected_is_service_found=*/true, /*expected_can_check_reputation=*/true); @@ -1554,7 +1606,7 @@ IsSameThreatSource(ThreatSource::NATIVE_PVER5_REAL_TIME), _, _, _)) .Times(1); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + url_checker_delegate_->WaitForStartDisplayingBlockingPageHelper(); CheckHashRealTimeMetrics(/*expected_local_match_result=*/false, /*expected_is_service_found=*/true, /*expected_can_check_reputation=*/true); @@ -1589,7 +1641,7 @@ IsSameThreatSource(ThreatSource::UNKNOWN), _, _, _)) .Times(1); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + url_checker_delegate_->WaitForStartDisplayingBlockingPageHelper(); CheckHashRealTimeMetrics(/*expected_local_match_result=*/false, /*expected_is_service_found=*/false, /*expected_can_check_reputation=*/true); @@ -1626,7 +1678,7 @@ IsSameThreatSource(ThreatSource::UNKNOWN), _, _, _)) .Times(1); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + url_checker_delegate_->WaitForStartDisplayingBlockingPageHelper(); CheckHashRealTimeMetrics(/*expected_local_match_result=*/false, /*expected_is_service_found=*/true, /*expected_can_check_reputation=*/true); @@ -1666,7 +1718,7 @@ .Times(1); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + url_checker_delegate_->WaitForStartDisplayingBlockingPageHelper(); ValidateCheckUrlTimeTakenMetrics(/*expected_hprt_log_count=*/0, /*expected_urt_log_count=*/1, /*expected_hpd_log_count=*/0); @@ -1718,7 +1770,7 @@ SendUrlRealTimeAndHashRealTimeDiscrepancyReport(_, _)) .Times(0); - task_environment_.RunUntilIdle(); + url_checker_delegate_->WaitForStartDisplayingBlockingPageHelper(); histogram_tester_.ExpectBucketCount( /*name=*/ @@ -1765,7 +1817,7 @@ SendUrlRealTimeAndHashRealTimeDiscrepancyReport(_, _)) .Times(0); - task_environment_.RunUntilIdle(); + url_checker_delegate_->WaitForStartDisplayingBlockingPageHelper(); histogram_tester_.ExpectBucketCount( /*name=*/ @@ -1799,8 +1851,7 @@ url, /*match=*/false, /*logging_details=*/std::nullopt); - base::MockCallback<SafeBrowsingUrlCheckerImpl::NativeCheckUrlCallback> - callback; + WaitableNativeCheckUrlCallback callback; EXPECT_CALL( callback, Run(/*proceed=*/true, /*showed_interstitial=*/false, @@ -1827,7 +1878,7 @@ .Times(1); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + callback.Wait(); histogram_tester_.ExpectBucketCount( /*name=*/ @@ -1893,7 +1944,7 @@ .Times(1); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + url_checker_delegate_->WaitForStartDisplayingBlockingPageHelper(); histogram_tester_.ExpectBucketCount( /*name=*/ @@ -1943,7 +1994,7 @@ SendUrlRealTimeAndHashRealTimeDiscrepancyReport(_, _)) .Times(0); - task_environment_.RunUntilIdle(); + url_checker_delegate_->WaitForStartDisplayingBlockingPageHelper(); // The SendUrlRealTimeAndHashRealTimeDiscrepancyReport method should not be // called because there is no discrepancy in the verdicts from URL real-time @@ -1953,7 +2004,7 @@ .Times(0); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + url_checker_delegate_->WaitForStartDisplayingBlockingPageHelper(); histogram_tester_.ExpectBucketCount( /*name=*/ @@ -1993,8 +2044,7 @@ url, /*match=*/false, /*logging_details=*/std::nullopt); - base::MockCallback<SafeBrowsingUrlCheckerImpl::NativeCheckUrlCallback> - callback; + WaitableNativeCheckUrlCallback callback; EXPECT_CALL( callback, Run(/*proceed=*/true, /*showed_interstitial=*/false, @@ -2011,7 +2061,7 @@ .Times(0); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + callback.Wait(); histogram_tester_.ExpectBucketCount( /*name=*/ @@ -2051,8 +2101,7 @@ url_lookup_service_->SetThreatTypeForUrl(url, SB_THREAT_TYPE_SAFE, /*should_complete_lookup=*/true); - base::MockCallback<SafeBrowsingUrlCheckerImpl::NativeCheckUrlCallback> - callback; + WaitableNativeCheckUrlCallback callback; safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); // The SendUrlRealTimeAndHashRealTimeDiscrepancyReport method should not be @@ -2061,7 +2110,7 @@ SendUrlRealTimeAndHashRealTimeDiscrepancyReport(_, _)) .Times(0); - task_environment_.RunUntilIdle(); + callback.Wait(); histogram_tester_.ExpectBucketCount( /*name=*/ @@ -2101,7 +2150,7 @@ .Times(1); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + url_checker_delegate_->WaitForStartDisplayingBlockingPageHelper(); CheckHashRealTimeMetrics(/*expected_local_match_result=*/std::nullopt, /*expected_is_service_found=*/std::nullopt, /*expected_can_check_reputation=*/true); @@ -2118,8 +2167,7 @@ hash_realtime_utils::HashRealTimeSelection::kNone); GURL url(kAllowlistedUrl); - base::MockCallback<SafeBrowsingUrlCheckerImpl::NativeCheckUrlCallback> - callback; + WaitableNativeCheckUrlCallback callback; EXPECT_CALL(callback, Run(/*proceed=*/true, /*showed_interstitial=*/false, /*has_post_commit_interstitial_skipped=*/false, @@ -2129,7 +2177,7 @@ .Times(0); safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get()); - task_environment_.RunUntilIdle(); + callback.Wait(); ValidateCheckUrlTimeTakenMetrics(/*expected_hprt_log_count=*/0, /*expected_urt_log_count=*/0, /*expected_hpd_log_count=*/0); @@ -2184,10 +2232,9 @@ url_lookup_service_->SetThreatTypeForUrl(url, SB_THREAT_TYPE_SAFE, /*should_complete_lookup=*/true); base::HistogramTester urt_histogram_tester; - base::MockCallback<SafeBrowsingUrlCheckerImpl::NativeCheckUrlCallback> - urt_callback; + WaitableNativeCheckUrlCallback urt_callback; urt_safe_browsing_url_checker->CheckUrl(url, "GET", urt_callback.Get()); - task_environment_.RunUntilIdle(); + urt_callback.Wait(); if (test_case.expected_all_stores_available_log.has_value()) { urt_histogram_tester.ExpectUniqueSample( "SafeBrowsing.RT.AllStoresAvailable", @@ -2216,10 +2263,9 @@ url, SB_THREAT_TYPE_SAFE, /*should_fail_lookup=*/false, /*should_delay_lookup=*/false); base::HistogramTester hprt_histogram_tester; - base::MockCallback<SafeBrowsingUrlCheckerImpl::NativeCheckUrlCallback> - hprt_callback; + WaitableNativeCheckUrlCallback hprt_callback; hprt_safe_browsing_url_checker->CheckUrl(url, "GET", hprt_callback.Get()); - task_environment_.RunUntilIdle(); + hprt_callback.Wait(); if (test_case.expected_all_stores_available_log.has_value()) { hprt_histogram_tester.ExpectUniqueSample( "SafeBrowsing.HPRT.AllStoresAvailable",
diff --git a/components/saved_tab_groups/internal/tab_group_sync_service_unittest.cc b/components/saved_tab_groups/internal/tab_group_sync_service_unittest.cc index 5bd55468..409ad44 100644 --- a/components/saved_tab_groups/internal/tab_group_sync_service_unittest.cc +++ b/components/saved_tab_groups/internal/tab_group_sync_service_unittest.cc
@@ -205,12 +205,13 @@ pref_service_.registry()->RegisterDictionaryPref( prefs::kLocallyClosedRemoteTabGroupIds, base::Value::Dict()); pref_service_.registry()->RegisterBooleanPref( - prefs::kDataSharingHasShownVersionUpdatedMessage, false); + prefs::kEligibleForVersionUpdatedMessage, false); pref_service_.registry()->RegisterBooleanPref( - prefs::kDataSharingHasShownVersionOutOfDateInstantMessage, false); + prefs::kEligibleForVersionOutOfDateInstantMessage, false); pref_service_.registry()->RegisterBooleanPref( - prefs::kDataSharingHasDismissedVersionOutOfDatePersistentMessage, - false); + prefs::kEligibleForVersionOutOfDatePersistentMessage, false); + pref_service_.registry()->RegisterBooleanPref( + prefs::kHasShownAnyVersionOutOfDateMessage, false); auto metrics_logger = std::make_unique<TabGroupSyncMetricsLoggerImpl>(&device_info_tracker_);
diff --git a/components/saved_tab_groups/internal/versioning_message_controller_impl.cc b/components/saved_tab_groups/internal/versioning_message_controller_impl.cc index 0d51344..ca41a5a 100644 --- a/components/saved_tab_groups/internal/versioning_message_controller_impl.cc +++ b/components/saved_tab_groups/internal/versioning_message_controller_impl.cc
@@ -17,24 +17,14 @@ data_sharing::features::kDataSharingEnableUpdateChromeUI); } -bool MeetsEligibilityCriteria( - PrefService* pref_service, - VersioningMessageController::MessageType message_type) { - switch (message_type) { - case VersioningMessageController::MessageType:: - VERSION_OUT_OF_DATE_INSTANT_MESSAGE: - return !pref_service->GetBoolean( - prefs::kDataSharingHasShownVersionOutOfDateInstantMessage); - case VersioningMessageController::MessageType:: - VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE: - return !pref_service->GetBoolean( - prefs::kDataSharingHasDismissedVersionOutOfDatePersistentMessage); - case VersioningMessageController::MessageType::VERSION_UPDATED_MESSAGE: - return !pref_service->GetBoolean( - prefs::kDataSharingHasShownVersionUpdatedMessage); - default: - return false; +bool HasCurrentSharedTabGroups(TabGroupSyncService* tab_group_sync_service) { + for (const auto* saved_tab_group : tab_group_sync_service->ReadAllGroups()) { + if (saved_tab_group->collaboration_id().has_value()) { + return true; + } } + + return false; } } // namespace @@ -44,7 +34,6 @@ TabGroupSyncService* tab_group_sync_service) : pref_service_(pref_service), tab_group_sync_service_(tab_group_sync_service) { - ResetMessagePrefsOnStartup(); tab_group_sync_service_->AddObserver(this); } @@ -52,22 +41,53 @@ tab_group_sync_service_->RemoveObserver(this); } -void VersioningMessageControllerImpl::ResetMessagePrefsOnStartup() { - // On startup, reset the message prefs based on the state of the - // feature flag. +void VersioningMessageControllerImpl::ComputePrefsOnStartup() { + // On startup, read and compute the state of the prefs based on the feature + // flag and number of shared tab groups in the previous session. + if (IsVersionOutOfDate()) { - // If versioning is disabled, reset the pref used for showing the re-enabled - // message shown in the enabled state. - pref_service_->SetBoolean(prefs::kDataSharingHasShownVersionUpdatedMessage, + // Version is out-of-date. If there were shared tab groups last session, + // that means that the version just switched. Compute the pref states + // accordingly. + + // Determine if previous session had shared tab groups that make + // it eligible for the instant/persistent message. + const bool had_open_shared_tab_groups = + tab_group_sync_service_->HadSharedTabGroupsLastSession( + /*open_shared_tab_groups=*/true); + const bool had_any_shared_tab_groups = + tab_group_sync_service_->HadSharedTabGroupsLastSession( + /*open_shared_tab_groups=*/false); + + if (had_open_shared_tab_groups) { + pref_service_->SetBoolean( + prefs::kEligibleForVersionOutOfDateInstantMessage, true); + } + + if (had_any_shared_tab_groups) { + pref_service_->SetBoolean( + prefs::kEligibleForVersionOutOfDatePersistentMessage, true); + } + + // Always reset the 'updated' message eligibility when out of date. + pref_service_->SetBoolean(prefs::kEligibleForVersionUpdatedMessage, false); + } else { // Version is up-to-date. + + // Determine if eligible for the 'version updated' message. + const bool had_any_out_of_date_messages_before = + pref_service_->GetBoolean(prefs::kHasShownAnyVersionOutOfDateMessage); + + if (had_any_out_of_date_messages_before) { + pref_service_->SetBoolean(prefs::kEligibleForVersionUpdatedMessage, true); + } + + // Always reset the 'out-of-date' message eligibilities when up to date. + pref_service_->SetBoolean(prefs::kEligibleForVersionOutOfDateInstantMessage, false); - } else { - // If versioning is enabled, reset the prefs used for showing the instant - // and persistent messages shown in the disabled state. + pref_service_->SetBoolean(prefs::kHasShownAnyVersionOutOfDateMessage, + false); pref_service_->SetBoolean( - prefs::kDataSharingHasShownVersionOutOfDateInstantMessage, false); - pref_service_->SetBoolean( - prefs::kDataSharingHasDismissedVersionOutOfDatePersistentMessage, - false); + prefs::kEligibleForVersionOutOfDatePersistentMessage, false); } } @@ -88,27 +108,17 @@ bool VersioningMessageControllerImpl::ShouldShowMessageUi( MessageType message_type) { CHECK(is_initialized_); - bool is_version_out_of_date = IsVersionOutOfDate(); - bool had_open_shared_tab_groups = - tab_group_sync_service_->HadSharedTabGroupsLastSession( - /*open_shared_tab_groups=*/true); - bool had_shared_tab_groups = - tab_group_sync_service_->HadSharedTabGroupsLastSession( - /*open_shared_tab_groups=*/false); - // Determines if the message can be shown, considering past displays or - // dismissals. - bool meets_eligibility_criteria = - MeetsEligibilityCriteria(pref_service_, message_type); - switch (message_type) { case MessageType::VERSION_OUT_OF_DATE_INSTANT_MESSAGE: - return is_version_out_of_date && had_open_shared_tab_groups && - meets_eligibility_criteria; + return pref_service_->GetBoolean( + prefs::kEligibleForVersionOutOfDateInstantMessage); case MessageType::VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE: - return is_version_out_of_date && had_shared_tab_groups && - meets_eligibility_criteria; + return pref_service_->GetBoolean( + prefs::kEligibleForVersionOutOfDatePersistentMessage); case MessageType::VERSION_UPDATED_MESSAGE: - return !is_version_out_of_date && meets_eligibility_criteria; + return pref_service_->GetBoolean( + prefs::kEligibleForVersionUpdatedMessage) && + HasCurrentSharedTabGroups(tab_group_sync_service_); default: return false; } @@ -119,11 +129,17 @@ switch (message_type) { case MessageType::VERSION_OUT_OF_DATE_INSTANT_MESSAGE: pref_service_->SetBoolean( - prefs::kDataSharingHasShownVersionOutOfDateInstantMessage, true); + prefs::kEligibleForVersionOutOfDateInstantMessage, false); + pref_service_->SetBoolean(prefs::kHasShownAnyVersionOutOfDateMessage, + true); + break; + case MessageType::VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE: + pref_service_->SetBoolean(prefs::kHasShownAnyVersionOutOfDateMessage, + true); break; case MessageType::VERSION_UPDATED_MESSAGE: - pref_service_->SetBoolean( - prefs::kDataSharingHasShownVersionUpdatedMessage, true); + pref_service_->SetBoolean(prefs::kEligibleForVersionUpdatedMessage, + false); break; default: break; @@ -134,12 +150,14 @@ MessageType message_type) { if (message_type == MessageType::VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE) { pref_service_->SetBoolean( - prefs::kDataSharingHasDismissedVersionOutOfDatePersistentMessage, true); + prefs::kEligibleForVersionOutOfDatePersistentMessage, false); } } void VersioningMessageControllerImpl::OnInitialized() { is_initialized_ = true; + ComputePrefsOnStartup(); + for (auto& callback : pending_callbacks_) { std::move(callback).Run(); }
diff --git a/components/saved_tab_groups/internal/versioning_message_controller_impl.h b/components/saved_tab_groups/internal/versioning_message_controller_impl.h index fdf6629..fa798bd 100644 --- a/components/saved_tab_groups/internal/versioning_message_controller_impl.h +++ b/components/saved_tab_groups/internal/versioning_message_controller_impl.h
@@ -39,7 +39,7 @@ private: bool ShouldShowMessageUi(MessageType message_type); - void ResetMessagePrefsOnStartup(); + void ComputePrefsOnStartup(); raw_ptr<PrefService> pref_service_; raw_ptr<TabGroupSyncService> tab_group_sync_service_;
diff --git a/components/saved_tab_groups/internal/versioning_message_controller_impl_unittest.cc b/components/saved_tab_groups/internal/versioning_message_controller_impl_unittest.cc index 01934d4..762926fd 100644 --- a/components/saved_tab_groups/internal/versioning_message_controller_impl_unittest.cc +++ b/components/saved_tab_groups/internal/versioning_message_controller_impl_unittest.cc
@@ -14,6 +14,7 @@ #include "components/saved_tab_groups/public/pref_names.h" #include "components/saved_tab_groups/public/versioning_message_controller.h" #include "components/saved_tab_groups/test_support/mock_tab_group_sync_service.h" +#include "components/saved_tab_groups/test_support/saved_tab_group_test_utils.h" #include "testing/gtest/include/gtest/gtest.h" namespace tab_groups { @@ -23,19 +24,19 @@ class VersioningMessageControllerImplTest : public testing::Test { public: - VersioningMessageControllerImplTest() { + VersioningMessageControllerImplTest() + : tab_group1_(test::CreateTestSavedTabGroup()) { pref_service_.registry()->RegisterBooleanPref( - prefs::kDataSharingHasShownVersionOutOfDateInstantMessage, false); + prefs::kEligibleForVersionOutOfDateInstantMessage, false); pref_service_.registry()->RegisterBooleanPref( - prefs::kDataSharingHasDismissedVersionOutOfDatePersistentMessage, - false); + prefs::kEligibleForVersionOutOfDatePersistentMessage, false); pref_service_.registry()->RegisterBooleanPref( - prefs::kDataSharingHasShownVersionUpdatedMessage, false); + prefs::kEligibleForVersionUpdatedMessage, false); + pref_service_.registry()->RegisterBooleanPref( + prefs::kHasShownAnyVersionOutOfDateMessage, false); - SetTabGroupSyncServiceExpectation(/*has_shared_tab_groups=*/false, - /*has_open_shared_tab_groups=*/false); - controller_ = std::make_unique<VersioningMessageControllerImpl>( - &pref_service_, &mock_tab_group_sync_service_); + SetTabGroupSyncServiceExpectation(/*had_shared_tab_groups=*/false, + /*had_open_shared_tab_groups=*/false); } void SetPref(const std::string& pref_name, bool value) { @@ -56,7 +57,20 @@ .WillRepeatedly(testing::Return(had_open_shared_tab_groups)); } - void InitializeController() { controller_->OnInitialized(); } + void SetTabGroupSyncServiceCurrentExpectation(bool has_shared_tab_groups) { + if (has_shared_tab_groups) { + tab_group1_.SetCollaborationId(CollaborationId("collaboration_id")); + } + EXPECT_CALL(mock_tab_group_sync_service_, ReadAllGroups()) + .WillRepeatedly( + testing::Return(std::vector<const SavedTabGroup*>({&tab_group1_}))); + } + + void InitializeController() { + controller_ = std::make_unique<VersioningMessageControllerImpl>( + &pref_service_, &mock_tab_group_sync_service_); + controller_->OnInitialized(); + } void ExpectMessageUiShouldBeShown(MessageType message_type, bool expected_value) { @@ -72,190 +86,175 @@ run_loop.Run(); } + bool ShouldShowMessageUi(MessageType message_type) { + base::RunLoop run_loop; + bool actual_result = false; + + controller_->ShouldShowMessageUiAsync( + message_type, base::BindOnce( + [](base::RunLoop* run_loop, bool* out_actual_value, + bool received_value) { + *out_actual_value = received_value; + run_loop->Quit(); + }, + &run_loop, &actual_result)); + run_loop.Run(); + + return actual_result; + } + protected: base::test::TaskEnvironment task_environment_; TestingPrefServiceSimple pref_service_; MockTabGroupSyncService mock_tab_group_sync_service_; std::unique_ptr<VersioningMessageControllerImpl> controller_; base::test::ScopedFeatureList scoped_feature_list_; + SavedTabGroup tab_group1_; }; TEST_F(VersioningMessageControllerImplTest, - TestPrefs_Startup_VersionOutOfDate) { + ShouldShowMessageUiAsync_VersionOutOfDate_HasSharedGroups) { scoped_feature_list_.InitAndEnableFeature( data_sharing::features::kDataSharingEnableUpdateChromeUI); - SetPref(prefs::kDataSharingHasShownVersionOutOfDateInstantMessage, true); - SetPref(prefs::kDataSharingHasDismissedVersionOutOfDatePersistentMessage, - true); - SetPref(prefs::kDataSharingHasShownVersionUpdatedMessage, true); + SetTabGroupSyncServiceExpectation(/*had_shared_tab_groups=*/true, + /*had_open_shared_tab_groups=*/true); InitializeController(); - controller_ = std::make_unique<VersioningMessageControllerImpl>( - &pref_service_, &mock_tab_group_sync_service_); - EXPECT_TRUE( - GetPref(prefs::kDataSharingHasShownVersionOutOfDateInstantMessage)); - EXPECT_TRUE(GetPref( - prefs::kDataSharingHasDismissedVersionOutOfDatePersistentMessage)); - EXPECT_FALSE(GetPref(prefs::kDataSharingHasShownVersionUpdatedMessage)); + ShouldShowMessageUi(MessageType::VERSION_OUT_OF_DATE_INSTANT_MESSAGE)); + EXPECT_TRUE( + ShouldShowMessageUi(MessageType::VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE)); + EXPECT_FALSE(ShouldShowMessageUi(MessageType::VERSION_UPDATED_MESSAGE)); } -TEST_F(VersioningMessageControllerImplTest, TestPrefs_Startup_VersionUpdated) { +TEST_F(VersioningMessageControllerImplTest, + ShouldShowMessageUiAsync_VersionOutOfDate_NoSharedGroups) { + scoped_feature_list_.InitAndEnableFeature( + data_sharing::features::kDataSharingEnableUpdateChromeUI); + SetTabGroupSyncServiceExpectation(/*had_shared_tab_groups=*/false, + /*had_open_shared_tab_groups=*/false); + InitializeController(); + EXPECT_FALSE( + ShouldShowMessageUi(MessageType::VERSION_OUT_OF_DATE_INSTANT_MESSAGE)); + EXPECT_FALSE( + ShouldShowMessageUi(MessageType::VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE)); + EXPECT_FALSE(ShouldShowMessageUi(MessageType::VERSION_UPDATED_MESSAGE)); +} + +TEST_F(VersioningMessageControllerImplTest, + ShouldShowMessageUiAsync_VersionOutOfDate_NoOpenSharedGroups) { + scoped_feature_list_.InitAndEnableFeature( + data_sharing::features::kDataSharingEnableUpdateChromeUI); + SetTabGroupSyncServiceExpectation(/*had_shared_tab_groups=*/true, + /*had_open_shared_tab_groups=*/false); + InitializeController(); + EXPECT_FALSE( + ShouldShowMessageUi(MessageType::VERSION_OUT_OF_DATE_INSTANT_MESSAGE)); + EXPECT_TRUE( + ShouldShowMessageUi(MessageType::VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE)); + EXPECT_FALSE(ShouldShowMessageUi(MessageType::VERSION_UPDATED_MESSAGE)); +} + +TEST_F( + VersioningMessageControllerImplTest, + ShouldShowMessageUiAsync_VersionOutOfDate_HasShownButNotDismissedBefore) { + scoped_feature_list_.InitAndEnableFeature( + data_sharing::features::kDataSharingEnableUpdateChromeUI); + SetPref(prefs::kHasShownAnyVersionOutOfDateMessage, true); + SetPref(prefs::kEligibleForVersionOutOfDateInstantMessage, false); + SetPref(prefs::kEligibleForVersionOutOfDatePersistentMessage, true); + + InitializeController(); + EXPECT_FALSE( + ShouldShowMessageUi(MessageType::VERSION_OUT_OF_DATE_INSTANT_MESSAGE)); + EXPECT_TRUE( + ShouldShowMessageUi(MessageType::VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE)); + EXPECT_FALSE(ShouldShowMessageUi(MessageType::VERSION_UPDATED_MESSAGE)); +} + +TEST_F( + VersioningMessageControllerImplTest, + ShouldShowMessageUiAsync_VersionUpdatedMessage_VersionUpdated_NotShownIfOutOfDateMessageNeverShown) { scoped_feature_list_.InitAndDisableFeature( data_sharing::features::kDataSharingEnableUpdateChromeUI); - SetPref(prefs::kDataSharingHasShownVersionOutOfDateInstantMessage, true); - SetPref(prefs::kDataSharingHasDismissedVersionOutOfDatePersistentMessage, - true); - SetPref(prefs::kDataSharingHasShownVersionUpdatedMessage, true); + SetPref(prefs::kHasShownAnyVersionOutOfDateMessage, false); + SetTabGroupSyncServiceCurrentExpectation(/*has_shared_tab_groups*/ true); InitializeController(); - controller_ = std::make_unique<VersioningMessageControllerImpl>( - &pref_service_, &mock_tab_group_sync_service_); EXPECT_FALSE( - GetPref(prefs::kDataSharingHasShownVersionOutOfDateInstantMessage)); - EXPECT_FALSE(GetPref( - prefs::kDataSharingHasDismissedVersionOutOfDatePersistentMessage)); - EXPECT_TRUE(GetPref(prefs::kDataSharingHasShownVersionUpdatedMessage)); -} - -TEST_F(VersioningMessageControllerImplTest, - QueryIfMessageUiShouldBeShown_InstantMessage_VersionOutOfDate) { - scoped_feature_list_.InitAndEnableFeature( - data_sharing::features::kDataSharingEnableUpdateChromeUI); - SetTabGroupSyncServiceExpectation(/*has_shared_tab_groups=*/true, - /*has_open_shared_tab_groups=*/true); - InitializeController(); - ExpectMessageUiShouldBeShown(MessageType::VERSION_OUT_OF_DATE_INSTANT_MESSAGE, - true); + ShouldShowMessageUi(MessageType::VERSION_OUT_OF_DATE_INSTANT_MESSAGE)); + EXPECT_FALSE( + ShouldShowMessageUi(MessageType::VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE)); + EXPECT_FALSE(ShouldShowMessageUi(MessageType::VERSION_UPDATED_MESSAGE)); } TEST_F( VersioningMessageControllerImplTest, - QueryIfMessageUiShouldBeShown_InstantMessage_VersionOutOfDate_NoSharedGroups) { - scoped_feature_list_.InitAndEnableFeature( - data_sharing::features::kDataSharingEnableUpdateChromeUI); - SetTabGroupSyncServiceExpectation(/*has_shared_tab_groups=*/false, - /*has_open_shared_tab_groups=*/false); - InitializeController(); - ExpectMessageUiShouldBeShown(MessageType::VERSION_OUT_OF_DATE_INSTANT_MESSAGE, - false); -} - -TEST_F(VersioningMessageControllerImplTest, - QueryIfMessageUiShouldBeShown_InstantMessage_VersionOutOfDate_PrefSet) { - scoped_feature_list_.InitAndEnableFeature( - data_sharing::features::kDataSharingEnableUpdateChromeUI); - SetPref(prefs::kDataSharingHasShownVersionOutOfDateInstantMessage, true); - SetTabGroupSyncServiceExpectation(/*has_shared_tab_groups=*/true, - /*has_open_shared_tab_groups=*/true); - InitializeController(); - ExpectMessageUiShouldBeShown(MessageType::VERSION_OUT_OF_DATE_INSTANT_MESSAGE, - false); -} - -TEST_F(VersioningMessageControllerImplTest, - QueryIfMessageUiShouldBeShown_InstantMessage_VersionUpdated) { + ShouldShowMessageUiAsync_VersionUpdatedMessage_VersionUpdated_ShownIfOutOfDateMessageShownBefore) { scoped_feature_list_.InitAndDisableFeature( data_sharing::features::kDataSharingEnableUpdateChromeUI); + SetPref(prefs::kHasShownAnyVersionOutOfDateMessage, true); + SetTabGroupSyncServiceCurrentExpectation(/*has_shared_tab_groups*/ true); InitializeController(); - ExpectMessageUiShouldBeShown(MessageType::VERSION_OUT_OF_DATE_INSTANT_MESSAGE, - false); -} -TEST_F(VersioningMessageControllerImplTest, - QueryIfMessageUiShouldBeShown_PersistentMessage_VersionOutOfDate) { - scoped_feature_list_.InitAndEnableFeature( - data_sharing::features::kDataSharingEnableUpdateChromeUI); - SetTabGroupSyncServiceExpectation(/*has_shared_tab_groups=*/true, - /*has_open_shared_tab_groups=*/false); - InitializeController(); - ExpectMessageUiShouldBeShown( - MessageType::VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE, true); -} - -TEST_F( - VersioningMessageControllerImplTest, - QueryIfMessageUiShouldBeShown_PersistentMessage_VersionOutOfDate_NoSharedGroups) { - scoped_feature_list_.InitAndEnableFeature( - data_sharing::features::kDataSharingEnableUpdateChromeUI); - SetTabGroupSyncServiceExpectation(/*has_shared_tab_groups=*/false, - /*has_open_shared_tab_groups=*/false); - InitializeController(); - ExpectMessageUiShouldBeShown( - MessageType::VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE, false); -} - -TEST_F( - VersioningMessageControllerImplTest, - QueryIfMessageUiShouldBeShown_PersistentMessage_VersionOutOfDate_PrefSet) { - scoped_feature_list_.InitAndEnableFeature( - data_sharing::features::kDataSharingEnableUpdateChromeUI); - SetPref(prefs::kDataSharingHasDismissedVersionOutOfDatePersistentMessage, - true); - SetTabGroupSyncServiceExpectation(/*has_shared_tab_groups=*/true, - /*has_open_shared_tab_groups=*/false); - InitializeController(); - ExpectMessageUiShouldBeShown( - MessageType::VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE, false); -} - -TEST_F(VersioningMessageControllerImplTest, - QueryIfMessageUiShouldBeShown_PersistentMessage_VersionUpdated) { - scoped_feature_list_.InitAndDisableFeature( - data_sharing::features::kDataSharingEnableUpdateChromeUI); - InitializeController(); - ExpectMessageUiShouldBeShown( - MessageType::VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE, false); -} - -TEST_F(VersioningMessageControllerImplTest, - ExpectMessageUiShouldBeShown_ReenabledMessage_VersionOutOfDate) { - scoped_feature_list_.InitAndEnableFeature( - data_sharing::features::kDataSharingEnableUpdateChromeUI); - InitializeController(); - ExpectMessageUiShouldBeShown(MessageType::VERSION_UPDATED_MESSAGE, false); -} - -TEST_F(VersioningMessageControllerImplTest, - QueryIfMessageUiShouldBeShown_ReenabledMessage_VersionUpdated) { - scoped_feature_list_.InitAndDisableFeature( - data_sharing::features::kDataSharingEnableUpdateChromeUI); - InitializeController(); - ExpectMessageUiShouldBeShown(MessageType::VERSION_UPDATED_MESSAGE, true); -} - -TEST_F(VersioningMessageControllerImplTest, - QueryIfMessageUiShouldBeShown_ReenabledMessage_VersionUpdated_PrefSet) { - scoped_feature_list_.InitAndDisableFeature( - data_sharing::features::kDataSharingEnableUpdateChromeUI); - SetPref(prefs::kDataSharingHasShownVersionUpdatedMessage, true); - InitializeController(); - ExpectMessageUiShouldBeShown(MessageType::VERSION_UPDATED_MESSAGE, false); + EXPECT_FALSE( + ShouldShowMessageUi(MessageType::VERSION_OUT_OF_DATE_INSTANT_MESSAGE)); + EXPECT_FALSE( + ShouldShowMessageUi(MessageType::VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE)); + EXPECT_TRUE(ShouldShowMessageUi(MessageType::VERSION_UPDATED_MESSAGE)); } TEST_F(VersioningMessageControllerImplTest, OnMessageUiShown_InstantMessage) { + scoped_feature_list_.InitAndEnableFeature( + data_sharing::features::kDataSharingEnableUpdateChromeUI); + SetPref(prefs::kEligibleForVersionOutOfDateInstantMessage, true); + SetPref(prefs::kHasShownAnyVersionOutOfDateMessage, false); InitializeController(); controller_->OnMessageUiShown( MessageType::VERSION_OUT_OF_DATE_INSTANT_MESSAGE); - EXPECT_TRUE( - GetPref(prefs::kDataSharingHasShownVersionOutOfDateInstantMessage)); + EXPECT_FALSE(GetPref(prefs::kEligibleForVersionOutOfDateInstantMessage)); + EXPECT_TRUE(GetPref(prefs::kHasShownAnyVersionOutOfDateMessage)); } -TEST_F(VersioningMessageControllerImplTest, OnMessageUiShown_ReenabledMessage) { +TEST_F(VersioningMessageControllerImplTest, + OnMessageUiShown_PersistentMessage) { + scoped_feature_list_.InitAndEnableFeature( + data_sharing::features::kDataSharingEnableUpdateChromeUI); + SetPref(prefs::kEligibleForVersionOutOfDatePersistentMessage, true); + SetPref(prefs::kHasShownAnyVersionOutOfDateMessage, true); + InitializeController(); + controller_->OnMessageUiShown( + MessageType::VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE); + EXPECT_TRUE(GetPref(prefs::kEligibleForVersionOutOfDatePersistentMessage)); + EXPECT_TRUE(GetPref(prefs::kHasShownAnyVersionOutOfDateMessage)); +} + +TEST_F(VersioningMessageControllerImplTest, + OnMessageUiShown_VersionUpdatedMessage) { + scoped_feature_list_.InitAndDisableFeature( + data_sharing::features::kDataSharingEnableUpdateChromeUI); + SetPref(prefs::kEligibleForVersionUpdatedMessage, true); + InitializeController(); controller_->OnMessageUiShown(MessageType::VERSION_UPDATED_MESSAGE); - EXPECT_TRUE(GetPref(prefs::kDataSharingHasShownVersionUpdatedMessage)); + EXPECT_FALSE(GetPref(prefs::kEligibleForVersionUpdatedMessage)); } TEST_F(VersioningMessageControllerImplTest, OnMessageUiDismissed_PersistentMessage) { + scoped_feature_list_.InitAndEnableFeature( + data_sharing::features::kDataSharingEnableUpdateChromeUI); + SetPref(prefs::kEligibleForVersionOutOfDatePersistentMessage, true); InitializeController(); controller_->OnMessageUiDismissed( MessageType::VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE); - EXPECT_TRUE(GetPref( - prefs::kDataSharingHasDismissedVersionOutOfDatePersistentMessage)); + EXPECT_FALSE(GetPref(prefs::kEligibleForVersionOutOfDatePersistentMessage)); } TEST_F(VersioningMessageControllerImplTest, Initialization_QueuedCallbacksFlushed) { + scoped_feature_list_.InitAndEnableFeature( + data_sharing::features::kDataSharingEnableUpdateChromeUI); + controller_ = std::make_unique<VersioningMessageControllerImpl>( + &pref_service_, &mock_tab_group_sync_service_); bool callback_called = false; controller_->ShouldShowMessageUiAsync( MessageType::VERSION_OUT_OF_DATE_INSTANT_MESSAGE, @@ -263,9 +262,168 @@ [](bool* callback_called, bool result) { *callback_called = true; }, &callback_called)); EXPECT_FALSE(callback_called); - InitializeController(); + controller_->OnInitialized(); EXPECT_TRUE(callback_called); } +TEST_F(VersioningMessageControllerImplTest, MultipleRestarts) { + { + // Start with version up-to-date. + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature( + data_sharing::features::kDataSharingEnableUpdateChromeUI); + SetTabGroupSyncServiceExpectation(/*had_shared_tab_groups=*/true, + /*had_open_shared_tab_groups=*/true); + SetTabGroupSyncServiceCurrentExpectation(/*has_shared_tab_groups*/ true); + InitializeController(); + + EXPECT_FALSE( + ShouldShowMessageUi(MessageType::VERSION_OUT_OF_DATE_INSTANT_MESSAGE)); + EXPECT_FALSE(ShouldShowMessageUi( + MessageType::VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE)); + EXPECT_FALSE(ShouldShowMessageUi(MessageType::VERSION_UPDATED_MESSAGE)); + } + + { + // Restart with version out-of-date. + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + data_sharing::features::kDataSharingEnableUpdateChromeUI); + SetTabGroupSyncServiceExpectation(/*had_shared_tab_groups=*/true, + /*had_open_shared_tab_groups=*/true); + SetTabGroupSyncServiceCurrentExpectation(/*has_shared_tab_groups*/ false); + InitializeController(); + + EXPECT_TRUE( + ShouldShowMessageUi(MessageType::VERSION_OUT_OF_DATE_INSTANT_MESSAGE)); + EXPECT_TRUE(ShouldShowMessageUi( + MessageType::VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE)); + EXPECT_FALSE(ShouldShowMessageUi(MessageType::VERSION_UPDATED_MESSAGE)); + + // Don't show the messages yet. + } + + { + // Restart again with version out-of-date. Since no message was actually + // shown last session, they should still be eligible to be shown. + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + data_sharing::features::kDataSharingEnableUpdateChromeUI); + SetTabGroupSyncServiceExpectation(/*had_shared_tab_groups=*/false, + /*had_open_shared_tab_groups=*/false); + SetTabGroupSyncServiceCurrentExpectation(/*has_shared_tab_groups*/ false); + InitializeController(); + + EXPECT_TRUE( + ShouldShowMessageUi(MessageType::VERSION_OUT_OF_DATE_INSTANT_MESSAGE)); + EXPECT_TRUE(ShouldShowMessageUi( + MessageType::VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE)); + EXPECT_FALSE(ShouldShowMessageUi(MessageType::VERSION_UPDATED_MESSAGE)); + + controller_->OnMessageUiShown( + MessageType::VERSION_OUT_OF_DATE_INSTANT_MESSAGE); + controller_->OnMessageUiShown( + MessageType::VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE); + } + + { + // Restart with version out-of-date. Only persistent message can be shown + // here since it isn't dismissed yet. + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + data_sharing::features::kDataSharingEnableUpdateChromeUI); + SetTabGroupSyncServiceExpectation(/*had_shared_tab_groups=*/false, + /*had_open_shared_tab_groups=*/false); + SetTabGroupSyncServiceCurrentExpectation(/*has_shared_tab_groups*/ false); + InitializeController(); + + EXPECT_FALSE( + ShouldShowMessageUi(MessageType::VERSION_OUT_OF_DATE_INSTANT_MESSAGE)); + EXPECT_TRUE(ShouldShowMessageUi( + MessageType::VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE)); + EXPECT_FALSE(ShouldShowMessageUi(MessageType::VERSION_UPDATED_MESSAGE)); + + controller_->OnMessageUiShown( + MessageType::VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE); + controller_->OnMessageUiDismissed( + MessageType::VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE); + } + + { + // Restart with version out-of-date. No message can be shown since all the + // message have been already shown and dismissed. + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + data_sharing::features::kDataSharingEnableUpdateChromeUI); + SetTabGroupSyncServiceExpectation(/*had_shared_tab_groups=*/false, + /*had_open_shared_tab_groups=*/false); + SetTabGroupSyncServiceCurrentExpectation(/*has_shared_tab_groups*/ false); + InitializeController(); + + EXPECT_FALSE( + ShouldShowMessageUi(MessageType::VERSION_OUT_OF_DATE_INSTANT_MESSAGE)); + EXPECT_FALSE(ShouldShowMessageUi( + MessageType::VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE)); + EXPECT_FALSE(ShouldShowMessageUi(MessageType::VERSION_UPDATED_MESSAGE)); + } + + { + // Restart with version up-to-date. Expect IPH to be eligible to be shown. + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature( + data_sharing::features::kDataSharingEnableUpdateChromeUI); + SetTabGroupSyncServiceExpectation(/*had_shared_tab_groups=*/false, + /*had_open_shared_tab_groups=*/false); + SetTabGroupSyncServiceCurrentExpectation(/*has_shared_tab_groups*/ true); + InitializeController(); + + EXPECT_FALSE( + ShouldShowMessageUi(MessageType::VERSION_OUT_OF_DATE_INSTANT_MESSAGE)); + EXPECT_FALSE(ShouldShowMessageUi( + MessageType::VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE)); + EXPECT_TRUE(ShouldShowMessageUi(MessageType::VERSION_UPDATED_MESSAGE)); + + // Don't show the IPH yet. Show it in next session. + } + + { + // Restart with version up-to-date. IPH wasn't shown in last session, so it + // should still be eligible to be shown. + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature( + data_sharing::features::kDataSharingEnableUpdateChromeUI); + SetTabGroupSyncServiceExpectation(/*had_shared_tab_groups=*/false, + /*had_open_shared_tab_groups=*/false); + SetTabGroupSyncServiceCurrentExpectation(/*has_shared_tab_groups*/ true); + InitializeController(); + + EXPECT_FALSE( + ShouldShowMessageUi(MessageType::VERSION_OUT_OF_DATE_INSTANT_MESSAGE)); + EXPECT_FALSE(ShouldShowMessageUi( + MessageType::VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE)); + EXPECT_TRUE(ShouldShowMessageUi(MessageType::VERSION_UPDATED_MESSAGE)); + + controller_->OnMessageUiShown(MessageType::VERSION_UPDATED_MESSAGE); + } + + { + // Restart with version up-to-date. IPH shouldn't be shown as it was shown + // before. + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature( + data_sharing::features::kDataSharingEnableUpdateChromeUI); + SetTabGroupSyncServiceExpectation(/*had_shared_tab_groups=*/false, + /*had_open_shared_tab_groups=*/false); + SetTabGroupSyncServiceCurrentExpectation(/*has_shared_tab_groups*/ true); + InitializeController(); + + EXPECT_FALSE( + ShouldShowMessageUi(MessageType::VERSION_OUT_OF_DATE_INSTANT_MESSAGE)); + EXPECT_FALSE(ShouldShowMessageUi( + MessageType::VERSION_OUT_OF_DATE_PERSISTENT_MESSAGE)); + EXPECT_FALSE(ShouldShowMessageUi(MessageType::VERSION_UPDATED_MESSAGE)); + } +} + } // namespace } // namespace tab_groups
diff --git a/components/saved_tab_groups/public/pref_names.cc b/components/saved_tab_groups/public/pref_names.cc index a7e6cbf..c5f4d21 100644 --- a/components/saved_tab_groups/public/pref_names.cc +++ b/components/saved_tab_groups/public/pref_names.cc
@@ -46,11 +46,13 @@ registry->RegisterBooleanPref(prefs::kDidEnableSharedTabGroupsInLastSession, false); registry->RegisterBooleanPref( - prefs::kDataSharingHasShownVersionOutOfDateInstantMessage, false); + prefs::kEligibleForVersionOutOfDateInstantMessage, false); registry->RegisterBooleanPref( - prefs::kDataSharingHasDismissedVersionOutOfDatePersistentMessage, false); - registry->RegisterBooleanPref( - prefs::kDataSharingHasShownVersionUpdatedMessage, false); + prefs::kEligibleForVersionOutOfDatePersistentMessage, false); + registry->RegisterBooleanPref(prefs::kEligibleForVersionUpdatedMessage, + false); + registry->RegisterBooleanPref(prefs::kHasShownAnyVersionOutOfDateMessage, + false); } void KeepAccountSettingsPrefsOnlyForUsers(
diff --git a/components/saved_tab_groups/public/pref_names.h b/components/saved_tab_groups/public/pref_names.h index 013379a0..16e0df0 100644 --- a/components/saved_tab_groups/public/pref_names.h +++ b/components/saved_tab_groups/public/pref_names.h
@@ -76,18 +76,22 @@ // Prefs for Data Sharing (Versioning). // Stores whether the instant message prompting users to update chrome to -// continue using shared tab groups has been shown. -inline constexpr char kDataSharingHasShownVersionOutOfDateInstantMessage[] = - "data_sharing.has_shown_out_of_date_instant_message"; +// continue using shared tab groups should be shown. +inline constexpr char kEligibleForVersionOutOfDateInstantMessage[] = + "data_sharing.eligible_for_version_out_of_date_instant_message"; // Stores whether the persistent message prompting users to update chrome to -// continue using shared tab groups has been shown and dismissed by the user. -inline constexpr char - kDataSharingHasDismissedVersionOutOfDatePersistentMessage[] = - "data_sharing.has_dismissed_out_of_date_persistent_message"; +// continue using shared tab groups should be shown. +inline constexpr char kEligibleForVersionOutOfDatePersistentMessage[] = + "data_sharing.eligible_for_version_out_of_date_persistent_message"; // Stores whether the message that chrome has been updated to support shared tab -// groups has been shown. -inline constexpr char kDataSharingHasShownVersionUpdatedMessage[] = - "data_sharing.has_shown_version_updated_message"; +// groups should be shown. +inline constexpr char kEligibleForVersionUpdatedMessage[] = + "data_sharing.eligible_for_version_updated_message"; + +// Stores whether any message (persistent or instant) prompting the user to +// update chrome to continue using shared tab groups has been shown. +inline constexpr char kHasShownAnyVersionOutOfDateMessage[] = + "data_sharing.has_shown_any_version_out_of_date_message"; // Registers the Clear Browsing Data UI prefs. void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
diff --git a/content/browser/attribution_reporting/interop/parser.cc b/content/browser/attribution_reporting/interop/parser.cc index 7d479f8b..9d4d8ae 100644 --- a/content/browser/attribution_reporting/interop/parser.cc +++ b/content/browser/attribution_reporting/interop/parser.cc
@@ -380,6 +380,13 @@ : events.back().time, /*strictly_greater=*/true); + if (dict.contains("connection")) { + bool connected = *dict.FindBool("connection"); + events.emplace_back(time, + AttributionSimulationEvent::Connection(connected)); + return; + } + std::optional<SuitableOrigin> context_origin; AttributionReportingEligibility eligibility; bool fenced = false;
diff --git a/content/browser/attribution_reporting/interop/parser.h b/content/browser/attribution_reporting/interop/parser.h index dd9c959..66a6197 100644 --- a/content/browser/attribution_reporting/interop/parser.h +++ b/content/browser/attribution_reporting/interop/parser.h
@@ -72,7 +72,13 @@ int64_t request_id; }; - using Data = std::variant<StartRequest, Response, EndRequest>; + // TODO(crbug.com/426412563): Scope connection events to individual report + // URLs. + struct Connection { + bool connected; + }; + + using Data = std::variant<StartRequest, Response, EndRequest, Connection>; base::Time time; Data data;
diff --git a/content/browser/attribution_reporting/interop/runner.cc b/content/browser/attribution_reporting/interop/runner.cc index ef73f49..34abbd09 100644 --- a/content/browser/attribution_reporting/interop/runner.cc +++ b/content/browser/attribution_reporting/interop/runner.cc
@@ -81,6 +81,7 @@ #include "services/network/public/mojom/attribution.mojom.h" #include "services/network/test/test_url_loader_factory.h" #include "services/network/test/test_utils.h" +#include "third_party/abseil-cpp/absl/functional/overload.h" #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/tokens/tokens.h" #include "url/gurl.h" @@ -421,6 +422,7 @@ run_loop.Run(); if (delta.is_negative()) { + task_environment.FastForwardBy(base::TimeDelta()); break; } task_environment.FastForwardBy(delta); @@ -558,9 +560,36 @@ for (const auto& event : run.events) { task_environment.FastForwardBy(event.time - base::Time::Now()); - std::visit( - [&](const auto& data) { Handle(data, *manager->GetDataHostManager()); }, + absl::Overload{ + [&](const AttributionSimulationEvent::Connection& event) { + if (!event.connected) { + test_url_loader_factory.SetInterceptor( + base::BindLambdaForTesting([&](const network:: + ResourceRequest& req) { + test_url_loader_factory.AddResponse( + req.url, network::mojom::URLResponseHead::New(), + /*content=*/"", + network::URLLoaderCompletionStatus( + net::ERR_INTERNET_DISCONNECTED), + network::TestURLLoaderFactory::Redirects(), + network::TestURLLoaderFactory::ResponseProduceFlags:: + kSendHeadersOnNetworkError); + })); + } else { + test_url_loader_factory.SetInterceptor( + base::BindLambdaForTesting( + [&](const network::ResourceRequest& req) { + output.reports.emplace_back( + MakeReport(req, time_origin, hpke_key)); + test_url_loader_factory.AddResponse(req.url.spec(), + /*content=*/""); + })); + } + }, + [&](const auto& data) { + Handle(data, *manager->GetDataHostManager()); + }}, event.data); }
diff --git a/content/test/content_test_bundle_data.filelist b/content/test/content_test_bundle_data.filelist index f28e65f..174651b 100644 --- a/content/test/content_test_bundle_data.filelist +++ b/content/test/content_test_bundle_data.filelist
@@ -6447,6 +6447,8 @@ data/attribution_reporting/interop/attribution_scopes_smaller_scope_limit.json data/attribution_reporting/interop/basic.json data/attribution_reporting/interop/basic_aggregatable.json +data/attribution_reporting/interop/basic_disconnected.json +data/attribution_reporting/interop/basic_retry.json data/attribution_reporting/interop/channel_capacity.json data/attribution_reporting/interop/clamp_aggregatable_report_window.json data/attribution_reporting/interop/clamp_event_report_window.json
diff --git a/content/test/data/attribution_reporting/interop/basic_disconnected.json b/content/test/data/attribution_reporting/interop/basic_disconnected.json new file mode 100644 index 0000000..46706d0e --- /dev/null +++ b/content/test/data/attribution_reporting/interop/basic_disconnected.json
@@ -0,0 +1,70 @@ +{ + "description": "Report is never sent due to network connectivity", + "input": { + "registrations": [ + { + "timestamp": "0", + "registration_request": { + "context_origin": "https://source.test", + "Attribution-Reporting-Eligible": "navigation-source" + }, + "responses": [ + { + "url": "https://reporter.test/register-source", + "debug_permission": true, + "response": { + "Attribution-Reporting-Register-Source": { + "destination": "https://destination.test", + "source_event_id": "123", + "debug_reporting": true + } + } + } + ] + }, + { + "timestamp": "1000", + "registration_request": { + "context_origin": "https://destination.test" + }, + "responses": [ + { + "url": "https://reporter.test/register-trigger", + "response": { + "Attribution-Reporting-Register-Trigger": { + "event_trigger_data": [ + { + "trigger_data": "7" + } + ] + } + } + } + ] + }, + // Disables report sends. + { + "timestamp": "2000", + "connection": false + } + ] + }, + "output": { + "reports": [ + { + "payload": [ + { + "body": { + "attribution_destination": "https://destination.test", + "source_event_id": "123", + "source_site": "https://source.test" + }, + "type": "source-success" + } + ], + "report_time": "0", + "report_url": "https://reporter.test/.well-known/attribution-reporting/debug/verbose" + } + ] + } +}
diff --git a/content/test/data/attribution_reporting/interop/basic_retry.json b/content/test/data/attribution_reporting/interop/basic_retry.json new file mode 100644 index 0000000..b94bd79 --- /dev/null +++ b/content/test/data/attribution_reporting/interop/basic_retry.json
@@ -0,0 +1,87 @@ +{ + "description": "Report fails on initial send, sends on retry", + "input": { + "registrations": [ + { + "timestamp": "0", + "registration_request": { + "context_origin": "https://source.test", + "Attribution-Reporting-Eligible": "navigation-source" + }, + "responses": [ + { + "url": "https://reporter.test/register-source", + "debug_permission": true, + "response": { + "Attribution-Reporting-Register-Source": { + "destination": "https://destination.test", + "source_event_id": "123", + "debug_reporting": true + } + } + } + ] + }, + { + "timestamp": "1000", + "registration_request": { + "context_origin": "https://destination.test" + }, + "responses": [ + { + "url": "https://reporter.test/register-trigger", + "response": { + "Attribution-Reporting-Register-Trigger": { + "event_trigger_data": [ + { + "trigger_data": "7" + } + ] + } + } + } + ] + }, + // Forces report to fail first send attempt. + { + "timestamp": "172799000", + "connection": false + }, + // Retry occurs five minutes later. + { + "timestamp": "172800001", + "connection": true + } + ] + }, + "output": { + "reports": [ + { + "payload": [ + { + "body": { + "attribution_destination": "https://destination.test", + "source_event_id": "123", + "source_site": "https://source.test" + }, + "type": "source-success" + } + ], + "report_time": "0", + "report_url": "https://reporter.test/.well-known/attribution-reporting/debug/verbose" + }, + { + "payload": { + "attribution_destination": "https://destination.test", + "randomized_trigger_rate": 0.0024263, + "scheduled_report_time": "172800", + "source_event_id": "123", + "source_type": "navigation", + "trigger_data": "7" + }, + "report_url": "https://reporter.test/.well-known/attribution-reporting/report-event-attribution", + "report_time": "173100000" + } + ] + } +}
diff --git a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt index afb49277..9187e8a 100644 --- a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt
@@ -232,7 +232,8 @@ # Renderer Hung Possibly just Slow crbug.com/338574390 [ mac intel-0x3e9b angle-metal asan graphite-disabled ] ContextLost_WebGPUUnblockedAfterUserInitiatedReload [ Failure ] crbug.com/338574390 [ mac intel-0x3e9b angle-metal asan graphite-disabled ] GpuCrash_GPUProcessCrashesExactlyOncePerVisitToAboutGpuCrash [ Failure ] - +crbug.com/338574390 [ mac intel-0x3e9b angle-metal asan ] ContextLost_WebGLContextLostOverlyLargeUniform [ RetryOnFailure ] +crbug.com/338574390 [ mac intel-0x3e9b angle-metal asan ] GpuNormalTermination_NewWebGLNotBlocked [ RetryOnFailure ] ####################################################################### # Automated Entries After This Point - Do Not Manually Add Below Here #
diff --git a/content/test/gpu/gpu_tests/test_expectations/expected_color_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/expected_color_expectations.txt index 96e9715..bf35e88 100644 --- a/content/test/gpu/gpu_tests/test_expectations/expected_color_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/expected_color_expectations.txt
@@ -122,6 +122,9 @@ # Flakes on Intel Mac with a larger shifted image crbug.com/425653491 [ mac intel-0x3e9b angle-metal graphite-enabled ] ExpectedColor_MediaRecorderFromVideoElement [ Failure ] +# Flakes on Android DEMUXER_ERROR_COULD_NOT_OPEN +crbug.com/426594100 [ android android-pixel-2 graphite-disabled ] ExpectedColor_MediaRecorderFromVideoElement [ RetryOnFailure ] + ####################################################################### # Automated Entries After This Point - Do Not Manually Add Below Here # #######################################################################
diff --git a/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt index e917f43e..60353cb 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
@@ -156,6 +156,7 @@ crbug.com/371802469 [ mac intel ] WebCodecs_FrameSizeChange_hvc1.1.6.L123.00_camera [ Failure ] # Same with prefer-hardware crbug.com/371802469 [ amd-0x7340 angle-opengl asan graphite-disabled mac ] WebCodecs_Encode_camera_hvc1.1.6.L123.00_prefer-hardware [ Failure ] +crbug.com/371802469 [ amd-0x7340 angle-metal graphite-disabled mac ] WebCodecs_Encode_camera_hvc1.1.6.L123.00_prefer-hardware [ Failure ] crbug.com/389978730 [ win11 nvidia-0x2783 ] WebCodecs_EncodeColorSpace_av01.0.04M.08_prefer-hardware [ Failure ]
diff --git a/extensions/common/extension_features.cc b/extensions/common/extension_features.cc index 04c9252..c69a0f1 100644 --- a/extensions/common/extension_features.cc +++ b/extensions/common/extension_features.cc
@@ -200,10 +200,8 @@ BASE_FEATURE(kDisableDisableExtensionsExceptCommandLineSwitch, "DisableDisableExtensionsExceptCommandLineSwitch", -// TODO(crbug.com/419530940): Enable feature for Google Chrome Branding once -// ready. -#if BUILDFLAG(GOOGLE_CHROME_BRANDING) - base::FEATURE_DISABLED_BY_DEFAULT +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && !BUILDFLAG(IS_CHROMEOS) + base::FEATURE_ENABLED_BY_DEFAULT #else base::FEATURE_DISABLED_BY_DEFAULT #endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) @@ -223,13 +221,14 @@ BASE_FEATURE(kDisableExtensionsOnChromeUrlsSwitch, "DisableExtensionsOnChromeUrlsSwitch", -// TODO(crbug.com/419530940): Enable feature for Google Chrome Branding only -// once ready. -#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && !BUILDFLAG(IS_CHROMEOS) - base::FEATURE_DISABLED_BY_DEFAULT +// TODO (crbug.com/426554244): Determine if this switch should be +// removed for desktop-android builds as well. +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && !BUILDFLAG(IS_CHROMEOS) && \ + !BUILDFLAG(ENABLE_DESKTOP_ANDROID_EXTENSIONS) + base::FEATURE_ENABLED_BY_DEFAULT #else base::FEATURE_DISABLED_BY_DEFAULT -#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) && !BUILDFLAG(IS_CHROMEOS) +#endif ); BASE_FEATURE(kUserScriptUserExtensionToggle,
diff --git a/gpu/command_buffer/service/shared_image/egl_image_backing_factory_unittest.cc b/gpu/command_buffer/service/shared_image/egl_image_backing_factory_unittest.cc index f8b63dbc..7e50cc10 100644 --- a/gpu/command_buffer/service/shared_image/egl_image_backing_factory_unittest.cc +++ b/gpu/command_buffer/service/shared_image/egl_image_backing_factory_unittest.cc
@@ -499,12 +499,20 @@ DawnProcTable procs = dawn::native::GetProcs(); dawnProcSetProcs(&procs); +#ifdef WGPU_BREAKING_CHANGE_INSTANCE_FEATURES_LIMITS + static constexpr auto kTimedWaitAny = wgpu::InstanceFeatureName::TimedWaitAny; + wgpu::InstanceDescriptor instance_desc = { + .requiredFeatureCount = 1, + .requiredFeatures = &kTimedWaitAny, + }; +#else wgpu::InstanceDescriptor instance_desc = { .capabilities = { .timedWaitAnyEnable = true, }, }; +#endif dawn::native::Instance instance(&instance_desc); // Create a Dawn OpenGLES device.
diff --git a/gpu/command_buffer/service/shared_image/iosurface_image_backing.mm b/gpu/command_buffer/service/shared_image/iosurface_image_backing.mm index 7acecc5..4d00efe 100644 --- a/gpu/command_buffer/service/shared_image/iosurface_image_backing.mm +++ b/gpu/command_buffer/service/shared_image/iosurface_image_backing.mm
@@ -972,12 +972,16 @@ if (end_access_desc.fenceCount > 0) { // For write access, we would need to WaitForCommandsToBeScheduled // before the image is used by CoreAnimation or WebGL later. - // However, we defer the wait on this device until CoreAnimation - // or WebGL actually needs to access the image. This could avoid repeated - // and unnecessary waits. + // However, when it's not thread safe (DrDC is disabled), we defer the wait + // on this device until CoreAnimation or WebGL actually needs to access the + // image. This could avoid repeated and unnecessary waits. // TODO(b/328411251): Investigate whether this is needed if the access // is readonly. - iosurface_backing->AddWGPUDeviceWithPendingCommands(device_); + if (iosurface_backing->is_thread_safe()) { + dawn::native::metal::WaitForCommandsToBeScheduled(device_.Get()); + } else { + iosurface_backing->AddWGPUDeviceWithPendingCommands(device_); + } } texture_ = nullptr; @@ -1884,7 +1888,14 @@ // glFlush on OpenGL. Defer the call until CoreAnimation, Dawn, or another // ANGLE EGLDisplay needs to access to avoid unnecessary overhead. This also // ensures that the Metal shared event enqueued above is eventually flushed. - AddEGLDisplayWithPendingCommands(display); + if (is_thread_safe()) { + // With DrDC and Graphite enabled, don't call + // AddEGLDisplayWithPendingCommands to avoid the GL context flush on + // the Viz thread. + eglWaitUntilWorkScheduledANGLE(display->GetDisplay()); + } else { + AddEGLDisplayWithPendingCommands(display); + } // When SwANGLE is used as the GL implementation, it holds an internal // texture. We have to call ReleaseTexImage here to trigger a copy from that
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm index b1bc798..9262e4a 100644 --- a/ios/chrome/browser/flags/about_flags.mm +++ b/ios/chrome/browser/flags/about_flags.mm
@@ -1540,12 +1540,6 @@ flag_descriptions::kScreenTimeIntegrationDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(kScreenTimeIntegration)}, #endif - {"ios-enable-delete-all-saved-credentials", - flag_descriptions::kIOSEnableDeleteAllSavedCredentialsName, - flag_descriptions::kIOSEnableDeleteAllSavedCredentialsDescription, - flags_ui::kOsIos, - FEATURE_VALUE_TYPE( - password_manager::features::kIOSEnableDeleteAllSavedCredentials)}, {"ios-shared-highlighting-color-change", flag_descriptions::kIOSSharedHighlightingColorChangeName, flag_descriptions::kIOSSharedHighlightingColorChangeDescription,
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc index 8e77c06c..af571d0 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -639,11 +639,6 @@ "When enabled, the user will be presented an animated, instructional " "promo showing how to move Chrome to their native iOS dock."; -extern const char kIOSEnableDeleteAllSavedCredentialsName[] = - "Enable delete all saved credentials in PWM"; -extern const char kIOSEnableDeleteAllSavedCredentialsDescription[] = - "When enabled, the delete all data button in PWM will be presented."; - const char kIOSEnablePasswordManagerTrustedVaultWidgetName[] = "Enable password settings encryption error widget"; const char kIOSEnablePasswordManagerTrustedVaultWidgetDescription[] =
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h index 9a2ae6a..0b2a218d 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -367,9 +367,6 @@ extern const char kIOSDockingPromoName[]; extern const char kIOSDockingPromoDescription[]; -extern const char kIOSEnableDeleteAllSavedCredentialsName[]; -extern const char kIOSEnableDeleteAllSavedCredentialsDescription[]; - extern const char kIOSEnablePasswordManagerTrustedVaultWidgetName[]; extern const char kIOSEnablePasswordManagerTrustedVaultWidgetDescription[];
diff --git a/ios/chrome/browser/home_customization/coordinator/home_customization_coordinator.mm b/ios/chrome/browser/home_customization/coordinator/home_customization_coordinator.mm index b819c492..34fd482 100644 --- a/ios/chrome/browser/home_customization/coordinator/home_customization_coordinator.mm +++ b/ios/chrome/browser/home_customization/coordinator/home_customization_coordinator.mm
@@ -78,7 +78,7 @@ - (void)start { image_fetcher::ImageFetcherService* imageFetcherService = - ImageFetcherServiceFactory::GetForProfile(self.browser->GetProfile()); + ImageFetcherServiceFactory::GetForProfile(self.profile); _mediator = [[HomeCustomizationMediator alloc] initWithPrefService:self.profile->GetPrefs()
diff --git a/ios/chrome/browser/intelligence/bwg/coordinator/bwg_coordinator.h b/ios/chrome/browser/intelligence/bwg/coordinator/bwg_coordinator.h index 72152468..9a01664 100644 --- a/ios/chrome/browser/intelligence/bwg/coordinator/bwg_coordinator.h +++ b/ios/chrome/browser/intelligence/bwg/coordinator/bwg_coordinator.h
@@ -11,11 +11,16 @@ namespace bwg { // Different BWG entry points. +// Logged as IOSBWGEntryPoint enum for the IOS.BWG.EntryPoint histogram. +// LINT.IfChange(IOSBWGEntryPoint) typedef NS_ENUM(NSInteger, EntryPoint) { EntryPointPromo, EntryPointOverflow, EntryPointAIHub, + EntryPointOmniboxChip, + kMaxValue = EntryPointOmniboxChip, }; +// LINT.ThenChange(/tools/metrics/histograms/metadata/ios/enums.xml:IOSBWGEntryPoint) } // namespace bwg
diff --git a/ios/chrome/browser/intelligence/bwg/coordinator/bwg_coordinator.mm b/ios/chrome/browser/intelligence/bwg/coordinator/bwg_coordinator.mm index e87514f2..59b3f74 100644 --- a/ios/chrome/browser/intelligence/bwg/coordinator/bwg_coordinator.mm +++ b/ios/chrome/browser/intelligence/bwg/coordinator/bwg_coordinator.mm
@@ -4,11 +4,13 @@ #import "ios/chrome/browser/intelligence/bwg/coordinator/bwg_coordinator.h" +#import "base/metrics/histogram_functions.h" #import "components/feature_engagement/public/tracker.h" #import "components/prefs/pref_service.h" #import "ios/chrome/browser/feature_engagement/model/tracker_factory.h" #import "ios/chrome/browser/intelligence/bwg/coordinator/bwg_mediator.h" #import "ios/chrome/browser/intelligence/bwg/coordinator/bwg_mediator_delegate.h" +#import "ios/chrome/browser/intelligence/bwg/metrics/bwg_metrics.h" #import "ios/chrome/browser/intelligence/bwg/ui/bwg_navigation_controller.h" #import "ios/chrome/browser/shared/model/browser/browser.h" #import "ios/chrome/browser/shared/model/prefs/pref_names.h" @@ -101,9 +103,14 @@ BOOL showConsent = [self shouldShowBWGConsent]; if (!showPromo && !showConsent) { + // Record the entry point metrics for the non-FRE case. + base::UmaHistogramEnumeration(kEntryPointHistogram, _entryPoint); + return NO; } + base::UmaHistogramEnumeration(kFREEntryPointHistogram, _entryPoint); + // If promo was shown outside the promos manager, ensure the promo doesn't // show through the promos manager. if (_entryPoint != bwg::EntryPointPromo) {
diff --git a/ios/chrome/browser/intelligence/bwg/coordinator/bwg_mediator.mm b/ios/chrome/browser/intelligence/bwg/coordinator/bwg_mediator.mm index 1085094..6464e461 100644 --- a/ios/chrome/browser/intelligence/bwg/coordinator/bwg_mediator.mm +++ b/ios/chrome/browser/intelligence/bwg/coordinator/bwg_mediator.mm
@@ -23,12 +23,6 @@ #import "ios/chrome/browser/shared/public/commands/open_new_tab_command.h" #import "url/gurl.h" -namespace { -// TODO(crbug.com/423816346): Change link when clicking on the attributed -// strings. -const char kFootnoteLinkURL[] = "https://google.com"; -} // namespace - @interface BWGMediator () // The base view controller to present UI. @@ -102,10 +96,9 @@ [_delegate dismissBWGFlow]; } -// Handles tap on learn about your choices. -- (void)handleLearnAboutYourChoicesTapped { - OpenNewTabCommand* command = - [OpenNewTabCommand commandWithURLFromChrome:GURL(kFootnoteLinkURL)]; +// Open a new tab page given a URL. +- (void)openNewTabWithURL:(const GURL&)URL { + OpenNewTabCommand* command = [OpenNewTabCommand commandWithURLFromChrome:URL]; [HandlerForProtocol(_browser->GetCommandDispatcher(), ApplicationCommands) openURLInNewTab:command]; }
diff --git a/ios/chrome/browser/intelligence/bwg/metrics/bwg_metrics.h b/ios/chrome/browser/intelligence/bwg/metrics/bwg_metrics.h index aebcc9c..0627493 100644 --- a/ios/chrome/browser/intelligence/bwg/metrics/bwg_metrics.h +++ b/ios/chrome/browser/intelligence/bwg/metrics/bwg_metrics.h
@@ -5,7 +5,13 @@ #ifndef IOS_CHROME_BROWSER_INTELLIGENCE_BWG_METRICS_BWG_METRICS_H_ #define IOS_CHROME_BROWSER_INTELLIGENCE_BWG_METRICS_BWG_METRICS_H_ -// UMA histogram key for IOS.BWG.Eligibility +// UMA histogram key for IOS.BWG.Eligibility. extern const char kEligibilityHistogram[]; +// UMA histogram key for IOS.BWG.EntryPoint. +extern const char kEntryPointHistogram[]; + +// UMA histogram key for IOS.BWG.FRE.EntryPoint. +extern const char kFREEntryPointHistogram[]; + #endif // IOS_CHROME_BROWSER_INTELLIGENCE_BWG_METRICS_BWG_METRICS_H_
diff --git a/ios/chrome/browser/intelligence/bwg/metrics/bwg_metrics.mm b/ios/chrome/browser/intelligence/bwg/metrics/bwg_metrics.mm index dd149ae9..c6b9db2 100644 --- a/ios/chrome/browser/intelligence/bwg/metrics/bwg_metrics.mm +++ b/ios/chrome/browser/intelligence/bwg/metrics/bwg_metrics.mm
@@ -5,3 +5,7 @@ #import "ios/chrome/browser/intelligence/bwg/metrics/bwg_metrics.h" const char kEligibilityHistogram[] = "IOS.BWG.Eligibility"; + +const char kEntryPointHistogram[] = "IOS.BWG.EntryPoint"; + +const char kFREEntryPointHistogram[] = "IOS.BWG.FRE.EntryPoint";
diff --git a/ios/chrome/browser/intelligence/bwg/model/BUILD.gn b/ios/chrome/browser/intelligence/bwg/model/BUILD.gn index e314bb08..3803f46 100644 --- a/ios/chrome/browser/intelligence/bwg/model/BUILD.gn +++ b/ios/chrome/browser/intelligence/bwg/model/BUILD.gn
@@ -39,6 +39,17 @@ ] } +source_set("config") { + sources = [ + "bwg_configuration.h", + "bwg_configuration.mm", + ] + deps = [ + "//base", + "//components/optimization_guide/proto:optimization_guide_proto", + ] +} + source_set("unit_tests") { testonly = true sources = [ "bwg_service_unittest.mm" ]
diff --git a/ios/chrome/browser/intelligence/bwg/model/bwg_configuration.h b/ios/chrome/browser/intelligence/bwg/model/bwg_configuration.h new file mode 100644 index 0000000..e3d45cc --- /dev/null +++ b/ios/chrome/browser/intelligence/bwg/model/bwg_configuration.h
@@ -0,0 +1,45 @@ +// 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_INTELLIGENCE_BWG_MODEL_BWG_CONFIGURATION_H_ +#define IOS_CHROME_BROWSER_INTELLIGENCE_BWG_MODEL_BWG_CONFIGURATION_H_ + +#import <Foundation/Foundation.h> +#import <UIKit/UIKit.h> + +#import <memory> + +class AuthenticationService; + +namespace ios::provider { +enum class BWGPageContextState; +} // namespace ios::provider + +namespace optimization_guide::proto { +class PageContext; +} // namespace optimization_guide::proto + +// BWGConfiguration is a configuration class that holds all the data necessary +// to start the BWG overlay. +@interface BWGConfiguration : NSObject + +// The base view controller to present the UI on. +@property(nonatomic, weak) UIViewController* baseViewController; + +// The PageContext for the current WebState. This is a unique_ptr, so subsequent +// calls to the getter will return a nullptr. +@property(nonatomic, assign) + std::unique_ptr<optimization_guide::proto::PageContext> + pageContext; + +// The authentication service to be used. +@property(nonatomic, assign) AuthenticationService* authService; + +// The state of the BWG PageContext. +@property(nonatomic, assign) + ios::provider::BWGPageContextState BWGPageContextState; + +@end + +#endif // IOS_CHROME_BROWSER_INTELLIGENCE_BWG_MODEL_BWG_CONFIGURATION_H_
diff --git a/ios/chrome/browser/intelligence/bwg/model/bwg_configuration.mm b/ios/chrome/browser/intelligence/bwg/model/bwg_configuration.mm new file mode 100644 index 0000000..016153f --- /dev/null +++ b/ios/chrome/browser/intelligence/bwg/model/bwg_configuration.mm
@@ -0,0 +1,25 @@ +// 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/intelligence/bwg/model/bwg_configuration.h" + +#import "base/check.h" +#import "components/optimization_guide/proto/features/common_quality_data.pb.h" + +@implementation BWGConfiguration { + // The current configuration's PageContext. + std::unique_ptr<optimization_guide::proto::PageContext> _pageContext; +} + +- (std::unique_ptr<optimization_guide::proto::PageContext>)pageContext { + CHECK(_pageContext.get()); + return std::move(_pageContext); +} + +- (void)setPageContext: + (std::unique_ptr<optimization_guide::proto::PageContext>)pageContext { + _pageContext = std::move(pageContext); +} + +@end
diff --git a/ios/chrome/browser/intelligence/bwg/ui/bwg_consent_mutator.h b/ios/chrome/browser/intelligence/bwg/ui/bwg_consent_mutator.h index 9e375a8a..205a9432 100644 --- a/ios/chrome/browser/intelligence/bwg/ui/bwg_consent_mutator.h +++ b/ios/chrome/browser/intelligence/bwg/ui/bwg_consent_mutator.h
@@ -5,6 +5,8 @@ #ifndef IOS_CHROME_BROWSER_INTELLIGENCE_BWG_UI_BWG_CONSENT_MUTATOR_H_ #define IOS_CHROME_BROWSER_INTELLIGENCE_BWG_UI_BWG_CONSENT_MUTATOR_H_ +#import "url/gurl.h" + // Mutator protocol for the view controller to communicate with the // `BWGConsentMediator`. @protocol BWGConsentMutator @@ -19,7 +21,7 @@ - (void)didCloseBWGPromo; // Handles tap on learn about your choices. -- (void)handleLearnAboutYourChoicesTapped; +- (void)openNewTabWithURL:(const GURL&)URL; @end
diff --git a/ios/chrome/browser/intelligence/bwg/ui/bwg_consent_view_controller.mm b/ios/chrome/browser/intelligence/bwg/ui/bwg_consent_view_controller.mm index e29c80b1..2ea2847 100644 --- a/ios/chrome/browser/intelligence/bwg/ui/bwg_consent_view_controller.mm +++ b/ios/chrome/browser/intelligence/bwg/ui/bwg_consent_view_controller.mm
@@ -14,6 +14,7 @@ #import "ios/chrome/common/ui/util/constraints_ui_util.h" #import "ios/chrome/grit/ios_strings.h" #import "ui/base/l10n/l10n_util_mac.h" +#import "url/gurl.h" namespace { @@ -40,20 +41,38 @@ // String constants for UI elements. NSString* const kBWGConsentFirstBoxTitleText = @"Lorem ipsum dolor sit amet, consecte tur adipiscing elit."; -NSString* const kBWGConsentFirstBoxBodyText = +NSString* const kBWGConsentFirstBoxBodyTextNonManagedAccount = @"Sed do eiusmod tempor incididunt. Sed do eiusmod tempor incididunt. Sed " @"do eiusmod tempor incididunt"; -NSString* const kBWGConsentSecondBoxTitleText = @"Lorem ipsum dolor sit amet"; -NSString* const kBWGConsentSecondBoxBodyText = +NSString* const kBWGConsentFirstBoxBodyTextManagedAccount = + @"Sed do eiusmod tempor incididunt. Sed do eiusmod tempor incididunt. Sed " + @"do eiusmod tempor incididunt. Do eiusmod tempor incididun."; +NSString* const kBWGConsentSecondBoxTitleTextNonManagedAccount = + @"Lorem ipsum dolor sit amet"; +NSString* const kBWGConsentSecondBoxTitleTextManagedAccount = + @"Lorem ipsum dolor sit amet sit amet"; +NSString* const kBWGConsentSecondBoxBodyTextNonManagedAccount = @"Lorem ipsum dolor sit amet, consecte tur adipiscing purposes. Sed do " - @"eiusmod tempor incididunt ut labore et dolore magna ali. eiusmod tempor "; -NSString* const kBWGConsentFootnoteText = + @"eiusmod tempor incididunt ut labore et dolore magna ali. Eiusmod tempor"; +NSString* const kBWGConsentSecondBoxBodyTextManagedAccount = + @"Eiusmod tempor incididunt ut labore et dolore magna ali. eiusmod tempor."; +NSString* const kBWGConsentFootnoteTextNonManagedAccount = @"Google terms dolor sit amet, Apps Privacy Notice tur adipiscing " @"purposes."; +NSString* const kBWGConsentFootnoteTextManagedAccount = + @"Your Privacy dolor sit amet."; // Action identifier on a tap on links in the footnote. -NSString* const kFootnoteLinkAction = @"footnoteLinkAction"; +NSString* const kFirstFootnoteLinkAction = @"firstFootnoteLinkAction"; +NSString* const kSecondFootnoteLinkAction = @"secondFootnoteLinkAction"; +NSString* const kFootnoteLinkActionManagedAccount = + @"footnoteLinkActionManagedAccount"; +// TODO(crbug.com/423816346): Change link when clicking on the attributed +// strings. +const char kFirstFootnoteLinkURL[] = "https://google.com"; +const char kSecondFootnoteLinkURL[] = "https://youtube.com"; +const char kFootnoteLinkURLManagedAccount[] = "https://gmail.com"; } // namespace @interface BWGConsentViewController () <UITextViewDelegate> @@ -96,7 +115,8 @@ // Creates an attributed string for the footnote with hyperlinks. - (NSAttributedString*)createFootnoteAttributedText { - NSString* text = kBWGConsentFootnoteText; + NSString* text = _isAccountManaged ? kBWGConsentFootnoteTextManagedAccount + : kBWGConsentFootnoteTextNonManagedAccount; NSMutableParagraphStyle* centeredTextStyle = [[NSMutableParagraphStyle alloc] init]; @@ -111,15 +131,29 @@ [[NSMutableAttributedString alloc] initWithString:text attributes:textAttributes]; - NSDictionary* linkAttributes = @{ - NSLinkAttributeName : kFootnoteLinkAction, + NSDictionary* firstLinkAttributes = @{ + NSLinkAttributeName : kFirstFootnoteLinkAction, + }; + + NSDictionary* secondLinkAttributes = @{ + NSLinkAttributeName : kSecondFootnoteLinkAction, + }; + + NSDictionary* linkAttributesManagedAccount = @{ + NSLinkAttributeName : kFootnoteLinkActionManagedAccount, }; // TODO(crbug.com/414778685): Add strings. NSRange firstLinkRange = [text rangeOfString:@"Google terms"]; - [attributedText addAttributes:linkAttributes range:firstLinkRange]; + [attributedText addAttributes:firstLinkAttributes range:firstLinkRange]; + NSRange secondLinkRange = [text rangeOfString:@"Apps Privacy Notice"]; - [attributedText addAttributes:linkAttributes range:secondLinkRange]; + [attributedText addAttributes:secondLinkAttributes range:secondLinkRange]; + + NSRange linkRangeManagedAccount = [text rangeOfString:@"Your Privacy"]; + [attributedText addAttributes:linkAttributesManagedAccount + range:linkRangeManagedAccount]; + return attributedText; } @@ -155,15 +189,21 @@ boxesStackView.translatesAutoresizingMaskIntoConstraints = NO; NSString* firstTitle = kBWGConsentFirstBoxTitleText; - NSString* firstBody = kBWGConsentFirstBoxBodyText; + NSString* firstBody = _isAccountManaged + ? kBWGConsentFirstBoxBodyTextManagedAccount + : kBWGConsentFirstBoxBodyTextNonManagedAccount; UIView* firstBox = [self createHorizontalBoxWithIcon:kInfoIconName boxView:[self createBoxWithTitle:firstTitle bodyText:firstBody]]; [boxesStackView addArrangedSubview:firstBox]; - NSString* secondTitle = kBWGConsentSecondBoxTitleText; - NSString* secondBody = kBWGConsentSecondBoxBodyText; + NSString* secondTitle = _isAccountManaged + ? kBWGConsentSecondBoxTitleTextManagedAccount + : kBWGConsentSecondBoxTitleTextNonManagedAccount; + NSString* secondBody = _isAccountManaged + ? kBWGConsentSecondBoxBodyTextManagedAccount + : kBWGConsentSecondBoxBodyTextNonManagedAccount; UIView* secondBox = [self createHorizontalBoxWithIcon:kCounterClockWiseSymbol boxView:[self createBoxWithTitle:secondTitle @@ -306,14 +346,29 @@ - (UIAction*)textView:(UITextView*)textView primaryActionForTextItem:(UITextItem*)textItem defaultAction:(UIAction*)defaultAction { - if (textItem.link && - [textItem.link.absoluteString isEqualToString:kFootnoteLinkAction]) { + if (!textItem.link) { + return defaultAction; + } + if ([textItem.link.absoluteString isEqualToString:kFirstFootnoteLinkAction]) { __weak __typeof(self) weakSelf = self; return [UIAction actionWithHandler:^(UIAction* action) { - [weakSelf.mutator handleLearnAboutYourChoicesTapped]; + [weakSelf.mutator openNewTabWithURL:GURL(kFirstFootnoteLinkURL)]; }]; } - + if ([textItem.link.absoluteString + isEqualToString:kSecondFootnoteLinkAction]) { + __weak __typeof(self) weakSelf = self; + return [UIAction actionWithHandler:^(UIAction* action) { + [weakSelf.mutator openNewTabWithURL:GURL(kSecondFootnoteLinkURL)]; + }]; + } + if ([textItem.link.absoluteString + isEqualToString:kFootnoteLinkActionManagedAccount]) { + __weak __typeof(self) weakSelf = self; + return [UIAction actionWithHandler:^(UIAction* action) { + [weakSelf.mutator openNewTabWithURL:GURL(kFootnoteLinkURLManagedAccount)]; + }]; + } return defaultAction; }
diff --git a/ios/chrome/browser/providers/bwg/chromium_bwg.mm b/ios/chrome/browser/providers/bwg/chromium_bwg.mm index 2f5015e0f..5ab103d 100644 --- a/ios/chrome/browser/providers/bwg/chromium_bwg.mm +++ b/ios/chrome/browser/providers/bwg/chromium_bwg.mm
@@ -19,11 +19,14 @@ return nullptr; } +// TODO(crbug.com/422506000): Remove this once the provider is migrated. void StartBwgOverlay( UIViewController* base_view_controller, raw_ptr<AuthenticationService> auth_service, std::unique_ptr<optimization_guide::proto::PageContext> page_context) {} +void StartBwgOverlay(BWGConfiguration* bwg_configuration) {} + const std::u16string GetPageContextShouldDetachScript() { return kShouldDetachPageContextScript; }
diff --git a/ios/chrome/browser/settings/ui_bundled/clear_browsing_data/quick_delete_coordinator.mm b/ios/chrome/browser/settings/ui_bundled/clear_browsing_data/quick_delete_coordinator.mm index 56ef661..8b4a7b5 100644 --- a/ios/chrome/browser/settings/ui_bundled/clear_browsing_data/quick_delete_coordinator.mm +++ b/ios/chrome/browser/settings/ui_bundled/clear_browsing_data/quick_delete_coordinator.mm
@@ -191,7 +191,7 @@ self.browser->GetWebStateList(), beginTime, endTime, cachedTabsInfo); TabGroupService* groupService = - TabGroupServiceFactory::GetForProfile(self.browser->GetProfile()); + TabGroupServiceFactory::GetForProfile(self.profile); std::set<tab_groups::TabGroupId> sharedGroups; if (groupService) { for (const TabGroup* group : webStateList->GetGroups()) {
diff --git a/ios/chrome/browser/settings/ui_bundled/password/password_manager_ui_features.h b/ios/chrome/browser/settings/ui_bundled/password/password_manager_ui_features.h index a45f052..91413c9 100644 --- a/ios/chrome/browser/settings/ui_bundled/password/password_manager_ui_features.h +++ b/ios/chrome/browser/settings/ui_bundled/password/password_manager_ui_features.h
@@ -16,10 +16,6 @@ // without a passcode set. BASE_DECLARE_FEATURE(kIOSEnablePasscodeSettings); -// Feature switch for the logic that allows the user to delete all saved -// credentials in PWM. -BASE_DECLARE_FEATURE(kIOSEnableDeleteAllSavedCredentials); - // Feature switch for adding or not Suggest Strong Password field in the add // password page. BASE_DECLARE_FEATURE(kSuggestStrongPasswordInAddPassword);
diff --git a/ios/chrome/browser/settings/ui_bundled/password/password_manager_ui_features.mm b/ios/chrome/browser/settings/ui_bundled/password/password_manager_ui_features.mm index 6eca137..22652f27 100644 --- a/ios/chrome/browser/settings/ui_bundled/password/password_manager_ui_features.mm +++ b/ios/chrome/browser/settings/ui_bundled/password/password_manager_ui_features.mm
@@ -10,10 +10,6 @@ "IOSEnablePasscodeSettings", base::FEATURE_ENABLED_BY_DEFAULT); -BASE_FEATURE(kIOSEnableDeleteAllSavedCredentials, - "IOSEnableDeleteAllSavedCredentials", - base::FEATURE_ENABLED_BY_DEFAULT); - BASE_FEATURE(kSuggestStrongPasswordInAddPassword, "SuggestStrongPasswordInAddPassword", base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/ios/chrome/browser/settings/ui_bundled/password/password_settings/password_settings_coordinator_unittest.mm b/ios/chrome/browser/settings/ui_bundled/password/password_settings/password_settings_coordinator_unittest.mm index d631561..f9d5314c 100644 --- a/ios/chrome/browser/settings/ui_bundled/password/password_settings/password_settings_coordinator_unittest.mm +++ b/ios/chrome/browser/settings/ui_bundled/password/password_settings/password_settings_coordinator_unittest.mm
@@ -227,9 +227,6 @@ // triggered. TEST_F(PasswordSettingsCoordinatorTest, PasswordSettingsDeleteAllDataRecordedOnce) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature( - password_manager::features::kIOSEnableDeleteAllSavedCredentials); StartCoordinatorSkippingAuth(/*skip_auth_on_start=*/NO); EXPECT_EQ(user_action_tester.GetActionCount(
diff --git a/ios/chrome/browser/settings/ui_bundled/password/password_settings/password_settings_view_controller.mm b/ios/chrome/browser/settings/ui_bundled/password/password_settings/password_settings_view_controller.mm index e0b1b76b..76aebf5 100644 --- a/ios/chrome/browser/settings/ui_bundled/password/password_settings/password_settings_view_controller.mm +++ b/ios/chrome/browser/settings/ui_bundled/password/password_settings/password_settings_view_controller.mm
@@ -328,8 +328,6 @@ toSectionWithIdentifier:SectionIdentifierImportPasswordsButton]; } - if (base::FeatureList::IsEnabled( - password_manager::features::kIOSEnableDeleteAllSavedCredentials)) { // Delete credentials button. [model addSectionWithIdentifier:SectionIdentifierDeleteCredentialsButton]; _deleteCredentialsItem = [self createDeleteCredentialsItem]; @@ -341,7 +339,6 @@ // Add footer for the delete credential section. [model setFooter:_deleteCredentialsFooterItem forSectionWithIdentifier:SectionIdentifierDeleteCredentialsButton]; - } if (_canBulkMoveLocalPasswordsToAccount) { [self updateBulkMovePasswordsToAccountSection]; @@ -1309,9 +1306,7 @@ } - (void)updateDeleteAllCredentialsSection { - if (_modelLoadStatus == ModelNotLoaded || - !base::FeatureList::IsEnabled( - password_manager::features::kIOSEnableDeleteAllSavedCredentials)) { + if (_modelLoadStatus == ModelNotLoaded) { return; }
diff --git a/ios/chrome/browser/settings/ui_bundled/password/password_settings/password_settings_view_controller_unittest.mm b/ios/chrome/browser/settings/ui_bundled/password/password_settings/password_settings_view_controller_unittest.mm index 3214715..c457ac8 100644 --- a/ios/chrome/browser/settings/ui_bundled/password/password_settings/password_settings_view_controller_unittest.mm +++ b/ios/chrome/browser/settings/ui_bundled/password/password_settings/password_settings_view_controller_unittest.mm
@@ -424,10 +424,6 @@ TEST_F(PasswordSettingsViewControllerTest, DeleteAllDataDisabledWhenUserNotEligible) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature( - password_manager::features::kIOSEnableDeleteAllSavedCredentials); - // Re-create the controller so that the enabled flag is picked up. CreateController(); [controller() setCanDeleteAllCredentials:NO]; @@ -439,10 +435,6 @@ TEST_F(PasswordSettingsViewControllerTest, DeleteAllDataButtonEnabledWhenUserEligible) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature( - password_manager::features::kIOSEnableDeleteAllSavedCredentials); - // Re-create the controller so that the enabled flag is picked up. CreateController(); [controller() setCanDeleteAllCredentials:YES];
diff --git a/ios/chrome/test/providers/bwg/OWNERS b/ios/chrome/test/providers/bwg/OWNERS new file mode 100644 index 0000000..386597d9 --- /dev/null +++ b/ios/chrome/test/providers/bwg/OWNERS
@@ -0,0 +1,3 @@ +adamta@google.com +joemerramos@google.com +nicolasmacbeth@google.com
diff --git a/ios/chrome/test/providers/bwg/test_bwg.mm b/ios/chrome/test/providers/bwg/test_bwg.mm index f263362..4512dbe 100644 --- a/ios/chrome/test/providers/bwg/test_bwg.mm +++ b/ios/chrome/test/providers/bwg/test_bwg.mm
@@ -21,11 +21,14 @@ return nullptr; } +// TODO(crbug.com/422506000): Remove this once the provider is migrated. void StartBwgOverlay( UIViewController* base_view_controller, raw_ptr<AuthenticationService> auth_service, std::unique_ptr<optimization_guide::proto::PageContext> page_context) {} +void StartBwgOverlay(BWGConfiguration* bwg_configuration) {} + const std::u16string GetPageContextShouldDetachScript() { return kShouldDetachPageContextScriptForTesting; }
diff --git a/ios/public/provider/chrome/browser/bwg/bwg_api.h b/ios/public/provider/chrome/browser/bwg/bwg_api.h index 959f97c..0b64a0ef 100644 --- a/ios/public/provider/chrome/browser/bwg/bwg_api.h +++ b/ios/public/provider/chrome/browser/bwg/bwg_api.h
@@ -15,8 +15,27 @@ class AuthenticationService; +@class BWGConfiguration; + namespace ios::provider { +// Enum representing the PageContext state of the BWG experience. This needs to +// stay in sync with GCRGeminiPageState. +enum class BWGPageContextState { + // Default state. + kUnknown, + // PageContext was successfully attached. + kSuccessfullyAttached, + // PageContext should be detached. + kShouldDetach, + // PageContext is protected. + kProtected, + // PageContext is present but likely to be blocked. + kBlocked, + // There was an error extracting the PageContext. + kError, +}; + // Creates request body data using a prompt and page context. std::string CreateRequestBody( std::string prompt, @@ -25,12 +44,15 @@ // Creates resource request for loading glic. std::unique_ptr<network::ResourceRequest> CreateResourceRequest(); -// Starts the overlay experience on a given view controller. +// TODO(crbug.com/422506000): Remove this once the provider is migrated. void StartBwgOverlay( UIViewController* base_view_controller, raw_ptr<AuthenticationService> auth_service, std::unique_ptr<optimization_guide::proto::PageContext> page_context); +// Starts the overlay experience with the given configuration. +void StartBwgOverlay(BWGConfiguration* bwg_configuration); + // Gets the portion of the PageContext script that checks whether PageContext // should be detached from the request. const std::u16string GetPageContextShouldDetachScript();
diff --git a/ios_internal b/ios_internal index cd9acb0..b8a1106 160000 --- a/ios_internal +++ b/ios_internal
@@ -1 +1 @@ -Subproject commit cd9acb0b818968f4583555dbb6ecf12a388fafbc +Subproject commit b8a110660c3ff24ecb3358f24baf562ceca2b41c
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn index 84e5cce..7f6e1ae0 100644 --- a/media/gpu/BUILD.gn +++ b/media/gpu/BUILD.gn
@@ -48,6 +48,7 @@ "//content/gpu:*", "//content/renderer:*", "//media/audio:unit_tests", + "//media/gpu/fuzzers/av1_builder/*", "//media/gpu/ipc/*", "//media/gpu/test/*", "//media/gpu/vaapi/*", @@ -776,3 +777,8 @@ ] seed_corpuses = [ "//media/test/data" ] } + +group("stream_builder_fuzzers") { + testonly = true + public_deps = [ "//media/gpu/fuzzers/av1_builder:av1_builder_fuzzer" ] +}
diff --git a/media/gpu/chromeos/vulkan_overlay_adaptor_test.cc b/media/gpu/chromeos/vulkan_overlay_adaptor_test.cc index 3430eaa2..ee1f21cd 100644 --- a/media/gpu/chromeos/vulkan_overlay_adaptor_test.cc +++ b/media/gpu/chromeos/vulkan_overlay_adaptor_test.cc
@@ -836,8 +836,10 @@ // raw, packed image data. auto packed_in_frame = VideoFrame::WrapExternalData( VideoPixelFormat::PIXEL_FORMAT_NV12, in_frame->coded_size(), - in_frame->visible_rect(), in_frame->coded_size(), image.Data(), - in_frame->coded_size().GetArea() * 3 / 2, base::TimeDelta()); + in_frame->visible_rect(), in_frame->coded_size(), + base::span(image.Data(), + static_cast<size_t>(in_frame->coded_size().GetArea() * 3 / 2)), + base::TimeDelta()); auto libyuv_out_frame = ProcessFrameLibyuv(packed_in_frame, in_fourcc, image.Size(), out_fourcc,
diff --git a/media/gpu/fuzzers/av1_builder/BUILD.gn b/media/gpu/fuzzers/av1_builder/BUILD.gn new file mode 100644 index 0000000..d55fcd43 --- /dev/null +++ b/media/gpu/fuzzers/av1_builder/BUILD.gn
@@ -0,0 +1,25 @@ +# Copyright 2025 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//media/media_options.gni") +import("//testing/libfuzzer/fuzzer_test.gni") +import("//third_party/libgav1/options.gni") +import("//third_party/protobuf/proto_library.gni") + +proto_library("av1_builder_fuzzer_inputs") { + sources = [ "av1_builder_fuzzer_inputs.proto" ] +} + +fuzzer_test("av1_builder_fuzzer") { + sources = [ "av1_builder_fuzzer.cc" ] + deps = [ + ":av1_builder_fuzzer_inputs", + "//base", + "//media/gpu", + "//third_party/libgav1:libgav1_parser", + "//third_party/libprotobuf-mutator", + ] + + seed_corpus = "seed" +}
diff --git a/media/gpu/fuzzers/av1_builder/av1_builder_fuzzer.cc b/media/gpu/fuzzers/av1_builder/av1_builder_fuzzer.cc new file mode 100644 index 0000000..935ec4f --- /dev/null +++ b/media/gpu/fuzzers/av1_builder/av1_builder_fuzzer.cc
@@ -0,0 +1,205 @@ +// 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 "media/gpu/av1_builder.h" + +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +#include "base/numerics/safe_conversions.h" +#include "media/gpu/fuzzers/av1_builder/av1_builder_fuzzer_inputs.pb.h" +#include "testing/libfuzzer/proto/lpm_interface.h" + +namespace { + +media::AV1BitstreamBuilder::SequenceHeader ConvertToAV1BuilderSequenceHeader( + const media::fuzzing::AV1SequenceHeader& sequence_header) { + media::AV1BitstreamBuilder::SequenceHeader seq_hdr{}; + seq_hdr.profile = sequence_header.profile(); + // The `operating_points_cnt_minus_1` is always provided by VEA as 0, not + // driver, so we clamp to `kMaxTemporalLayerNum - 1` if input is larger than + // that, to avoid CHECK failure in av1_builder. + seq_hdr.operating_points_cnt_minus_1 = + std::min(sequence_header.operating_points_cnt_minus_1(), + media::AV1BitstreamBuilder::kMaxTemporalLayerNum - 1); + const size_t level_size = + std::min(static_cast<size_t>(sequence_header.level_size()), + std::size(seq_hdr.level)); + for (size_t i = 0; i < level_size; ++i) { + seq_hdr.level[i] = sequence_header.level(i); + } + const size_t tier_size = + std::min(static_cast<size_t>(sequence_header.tier_size()), + std::size(seq_hdr.tier)); + for (size_t i = 0; i < tier_size; ++i) { + seq_hdr.tier[i] = sequence_header.tier(i); + } + seq_hdr.frame_width_bits_minus_1 = sequence_header.frame_width_bits_minus_1(); + seq_hdr.frame_height_bits_minus_1 = + sequence_header.frame_height_bits_minus_1(); + seq_hdr.width = sequence_header.width(); + seq_hdr.height = sequence_header.height(); + seq_hdr.use_128x128_superblock = sequence_header.use_128x128_superblock(); + seq_hdr.enable_filter_intra = sequence_header.enable_filter_intra(); + seq_hdr.enable_intra_edge_filter = sequence_header.enable_intra_edge_filter(); + seq_hdr.enable_interintra_compound = + sequence_header.enable_interintra_compound(); + seq_hdr.enable_masked_compound = sequence_header.enable_masked_compound(); + seq_hdr.enable_warped_motion = sequence_header.enable_warped_motion(); + seq_hdr.enable_dual_filter = sequence_header.enable_dual_filter(); + seq_hdr.enable_order_hint = sequence_header.enable_order_hint(); + seq_hdr.enable_jnt_comp = sequence_header.enable_jnt_comp(); + seq_hdr.enable_ref_frame_mvs = sequence_header.enable_ref_frame_mvs(); + seq_hdr.order_hint_bits_minus_1 = sequence_header.order_hint_bits_minus_1(); + seq_hdr.enable_superres = sequence_header.enable_superres(); + seq_hdr.enable_cdef = sequence_header.enable_cdef(); + seq_hdr.enable_restoration = sequence_header.enable_restoration(); + + return seq_hdr; +} + +libgav1::FrameType ConvertToFrameType(media::fuzzing::FrameType frame_type) { + switch (frame_type) { + case media::fuzzing::FrameType::KEY: + return libgav1::FrameType::kFrameKey; + case media::fuzzing::FrameType::INTER: + return libgav1::FrameType::kFrameInter; + case media::fuzzing::FrameType::INTRAONLY: + return libgav1::FrameType::kFrameIntraOnly; + case media::fuzzing::FrameType::SWITCH: + return libgav1::FrameType::kFrameSwitch; + } +} + +libgav1::LoopRestorationType ConvertToLoopRestorationType( + media::fuzzing::LoopRestorationType restoration_type) { + switch (restoration_type) { + case media::fuzzing::LoopRestorationType::NONE: + return libgav1::LoopRestorationType::kLoopRestorationTypeNone; + case media::fuzzing::LoopRestorationType::SWITCHABLE: + return libgav1::LoopRestorationType::kLoopRestorationTypeSwitchable; + case media::fuzzing::LoopRestorationType::WIENER: + return libgav1::LoopRestorationType::kLoopRestorationTypeWiener; + case media::fuzzing::LoopRestorationType::SGRPROJ: + return libgav1::LoopRestorationType::kLoopRestorationTypeSgrProj; + } +} + +media::AV1BitstreamBuilder::FrameHeader ConvertToAV1BuilderFrameHeader( + const media::fuzzing::AV1FrameHeader& frame_header) { + media::AV1BitstreamBuilder::FrameHeader pic_hdr{}; + pic_hdr.frame_type = ConvertToFrameType(frame_header.frame_type()); + pic_hdr.error_resilient_mode = frame_header.error_resilient_mode(); + pic_hdr.disable_cdf_update = frame_header.disable_cdf_update(); + + pic_hdr.base_qindex = frame_header.base_qindex(); + pic_hdr.separate_uv_delta_q = frame_header.separate_uv_delta_q(); + pic_hdr.delta_q_y_dc = frame_header.delta_q_y_dc(); + pic_hdr.delta_q_u_dc = frame_header.delta_q_u_dc(); + pic_hdr.delta_q_u_ac = frame_header.delta_q_u_ac(); + pic_hdr.delta_q_v_dc = frame_header.delta_q_v_dc(); + pic_hdr.delta_q_v_ac = frame_header.delta_q_v_ac(); + pic_hdr.using_qmatrix = frame_header.using_qmatrix(); + pic_hdr.qm_y = frame_header.qm_y(); + pic_hdr.qm_u = frame_header.qm_u(); + pic_hdr.qm_v = frame_header.qm_v(); + + pic_hdr.order_hint = frame_header.order_hint(); + + const size_t tier_size = + std::min(static_cast<size_t>(frame_header.filter_level_size()), + std::size(pic_hdr.filter_level)); + for (size_t i = 0; i < tier_size; ++i) { + pic_hdr.filter_level[i] = frame_header.filter_level(i); + } + pic_hdr.filter_level_u = frame_header.filter_level_u(); + pic_hdr.filter_level_v = frame_header.filter_level_v(); + pic_hdr.sharpness_level = frame_header.sharpness_level(); + pic_hdr.loop_filter_delta_enabled = frame_header.loop_filter_delta_enabled(); + pic_hdr.loop_filter_delta_update = frame_header.loop_filter_delta_update(); + pic_hdr.update_ref_delta = frame_header.update_ref_delta(); + + const size_t ref_deltas_size = + std::min(static_cast<size_t>(frame_header.loop_filter_ref_deltas_size()), + std::size(pic_hdr.loop_filter_ref_deltas)); + for (size_t i = 0; i < ref_deltas_size; ++i) { + pic_hdr.loop_filter_ref_deltas[i] = frame_header.loop_filter_ref_deltas(i); + } + pic_hdr.update_mode_delta = frame_header.update_mode_delta(); + const size_t mode_deltas_size = + std::min(static_cast<size_t>(frame_header.loop_filter_mode_deltas_size()), + std::size(pic_hdr.loop_filter_mode_deltas)); + for (size_t i = 0; i < mode_deltas_size; ++i) { + pic_hdr.loop_filter_mode_deltas[i] = + frame_header.loop_filter_mode_deltas(i); + } + pic_hdr.delta_lf_present = frame_header.delta_lf_present(); + pic_hdr.delta_lf_res = frame_header.delta_lf_res(); + pic_hdr.delta_lf_multi = frame_header.delta_lf_multi(); + pic_hdr.delta_q_present = frame_header.delta_q_present(); + pic_hdr.delta_q_res = frame_header.delta_q_res(); + + pic_hdr.primary_ref_frame = frame_header.primary_ref_frame(); + pic_hdr.refresh_frame_flags = frame_header.refresh_frame_flags(); + const size_t ref_frame_idx_size = + std::min(static_cast<size_t>(frame_header.ref_frame_idx_size()), + std::size(pic_hdr.ref_frame_idx)); + for (size_t i = 0; i < ref_frame_idx_size; ++i) { + pic_hdr.ref_frame_idx[i] = frame_header.ref_frame_idx(i); + } + const size_t ref_order_hint_size = + std::min(static_cast<size_t>(frame_header.ref_order_hint_size()), + std::size(pic_hdr.ref_order_hint)); + for (size_t i = 0; i < ref_order_hint_size; ++i) { + pic_hdr.ref_order_hint[i] = frame_header.ref_order_hint(i); + } + const size_t restoration_type_size = + std::min(static_cast<size_t>(frame_header.restoration_type_size()), + std::size(pic_hdr.restoration_type)); + for (size_t i = 0; i < restoration_type_size; ++i) { + pic_hdr.restoration_type[i] = + ConvertToLoopRestorationType(frame_header.restoration_type(i)); + } + pic_hdr.segment_number = frame_header.segment_number(); + pic_hdr.feature_data.fill({}); + const size_t feature_data_flat_size = + std::min(static_cast<size_t>(frame_header.feature_data_size()), + pic_hdr.feature_data.size() * pic_hdr.feature_data[0].size()); + for (size_t flat_idx = 0; flat_idx < feature_data_flat_size; ++flat_idx) { + size_t j = flat_idx / pic_hdr.feature_data[0].size(); + size_t i = flat_idx % pic_hdr.feature_data[0].size(); + pic_hdr.feature_data[j][i] = frame_header.feature_data(flat_idx); + } + pic_hdr.segmentation_temporal_update = + frame_header.segmentation_temporal_update(); + pic_hdr.segmentation_update_data = frame_header.segmentation_update_data(); + pic_hdr.segment_number = frame_header.segment_number(); + + return pic_hdr; +} + +} // namespace + +namespace media { +namespace fuzzing { + +DEFINE_PROTO_FUZZER(const AV1FrameOBUList& obu_list) { + for (const auto& obu : obu_list.frames()) { + AV1BitstreamBuilder::SequenceHeader seq_hdr = + ConvertToAV1BuilderSequenceHeader(obu.seq_hdr()); + + AV1BitstreamBuilder::FrameHeader pic_hdr = + ConvertToAV1BuilderFrameHeader(obu.frame_hdr()); + + AV1BitstreamBuilder seq_obu = + AV1BitstreamBuilder::BuildSequenceHeaderOBU(seq_hdr); + + AV1BitstreamBuilder frame_obu = + AV1BitstreamBuilder::BuildFrameHeaderOBU(seq_hdr, pic_hdr); + } +} + +} // namespace fuzzing +} // namespace media
diff --git a/media/gpu/fuzzers/av1_builder/av1_builder_fuzzer_inputs.proto b/media/gpu/fuzzers/av1_builder/av1_builder_fuzzer_inputs.proto new file mode 100644 index 0000000..4ff21fb --- /dev/null +++ b/media/gpu/fuzzers/av1_builder/av1_builder_fuzzer_inputs.proto
@@ -0,0 +1,113 @@ +// 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. + +syntax = "proto2"; + +package media.fuzzing; + +enum FrameType { + KEY = 0; + INTER = 1; + INTRAONLY = 2; + SWITCH = 3; +} + +enum LoopRestorationType { + NONE = 0; + SWITCHABLE = 1; + WIENER = 2; + SGRPROJ = 3; +} + +message AV1FrameHeader { + optional FrameType frame_type = 1; + optional bool error_resilient_mode = 2; + optional bool disable_cdf_update = 3; + optional bool disable_frame_end_update_cdf = 4; + optional uint32 base_qindex = 5; + optional bool separate_uv_delta_q = 6; + optional int32 delta_q_y_dc = 7; + optional int32 delta_q_u_dc = 8; + optional int32 delta_q_u_ac = 9; + optional int32 delta_q_v_dc = 10; + optional int32 delta_q_v_ac = 11; + optional bool using_qmatrix = 12; + optional uint32 qm_y = 13; + optional uint32 qm_u = 14; + optional uint32 qm_v = 15; + optional uint32 order_hint = 16; + repeated uint32 filter_level = 17; + optional uint32 filter_level_u = 18; + optional uint32 filter_level_v = 19; + optional uint32 sharpness_level = 20; + optional bool loop_filter_delta_enabled = 21; + optional bool loop_filter_delta_update = 22; + optional bool update_ref_delta = 23; + repeated int32 loop_filter_ref_deltas = 24; + optional bool update_mode_delta = 25; + repeated int32 loop_filter_mode_deltas = 26; + optional bool delta_lf_present = 27; + optional uint32 delta_lf_res = 28; + optional bool delta_lf_multi = 29; + optional bool delta_q_present = 30; + optional uint32 delta_q_res = 31; + optional uint32 primary_ref_frame = 32; + repeated uint32 ref_frame_idx = 33; + optional uint32 refresh_frame_flags = 34; + repeated uint32 ref_order_hint = 35; + optional uint32 cdef_damping_minus_3 = 36; + optional uint32 cdef_bits = 37; + repeated uint32 cdef_y_pri_strength = 38; + repeated uint32 cdef_y_sec_strength = 39; + repeated uint32 cdef_uv_pri_strength = 40; + repeated uint32 cdef_uv_sec_strength = 41; + repeated LoopRestorationType restoration_type = 42; + optional uint32 lr_unit_shift = 43; + optional uint32 lr_uv_shift = 44; + optional uint32 tx_mode = 45; + optional bool reduced_tx_set = 46; + optional bool segmentation_enabled = 47; + optional bool segmentation_update_map = 48; + optional bool segmentation_temporal_update = 49; + optional bool segmentation_update_data = 50; + optional uint32 segment_number = 51; + repeated uint32 feature_mask = 52; + repeated uint32 feature_data = 53; + optional bool allow_screen_content_tools = 54; + optional bool allow_intrabc = 55; + optional bool reference_select = 56; +} + +message AV1SequenceHeader { + optional uint32 profile = 1; + optional uint32 operating_points_cnt_minus_1 = 2; + repeated uint32 level = 3; + repeated uint32 tier = 4; + optional uint32 frame_width_bits_minus_1 = 5; + optional uint32 frame_height_bits_minus_1 = 6; + optional uint32 width = 7; + optional uint32 height = 8; + optional bool use_128x128_superblock = 9; + optional bool enable_filter_intra = 10; + optional bool enable_intra_edge_filter = 11; + optional bool enable_interintra_compound = 12; + optional bool enable_masked_compound = 13; + optional bool enable_warped_motion = 14; + optional bool enable_dual_filter = 15; + optional bool enable_order_hint = 16; + optional bool enable_jnt_comp = 17; + optional bool enable_ref_frame_mvs = 18; + optional uint32 order_hint_bits_minus_1 = 19; + optional bool enable_superres = 20; + optional bool enable_cdef = 21; + optional bool enable_restoration = 22; +} + +message AV1FrameOBUList { + message FrameHeader { + optional AV1SequenceHeader seq_hdr = 1; + optional AV1FrameHeader frame_hdr = 2; + } + repeated FrameHeader frames = 1; +}
diff --git a/media/gpu/fuzzers/av1_builder/seed/README.md b/media/gpu/fuzzers/av1_builder/seed/README.md new file mode 100644 index 0000000..b8d8bcf4 --- /dev/null +++ b/media/gpu/fuzzers/av1_builder/seed/README.md
@@ -0,0 +1,7 @@ +# AV1 builder fuzzing seed corpus + +## List of Test Files + +### av1-I-frame-1280x720.textproto + +This file was generated by parsing //media/test/data/av1-I-frame-1280x720 using libgav1 OBU parser and converting the result to a protobuf.
diff --git a/media/gpu/fuzzers/av1_builder/seed/av1-I-frame-1280x720.textproto b/media/gpu/fuzzers/av1_builder/seed/av1-I-frame-1280x720.textproto new file mode 100644 index 0000000..884d282 --- /dev/null +++ b/media/gpu/fuzzers/av1_builder/seed/av1-I-frame-1280x720.textproto
@@ -0,0 +1,139 @@ +frames { + seq_hdr { + profile: 0 + operating_points_cnt_minus_1: 0 + level: 5 + level: 0 + level: 0 + tier: 0 + tier: 0 + tier: 0 + frame_width_bits_minus_1: 10 + frame_height_bits_minus_1: 9 + width: 1280 + height: 720 + use_128x128_superblock: true + enable_filter_intra: true + enable_intra_edge_filter: true + enable_interintra_compound: false + enable_masked_compound: false + enable_warped_motion: false + enable_dual_filter: false + enable_order_hint: false + enable_jnt_comp: false + enable_ref_frame_mvs: false + order_hint_bits_minus_1: 0 + enable_superres: false + enable_cdef: true + enable_restoration: true + } + frame_hdr { + frame_type: KEY + error_resilient_mode: false + disable_cdf_update: false + disable_frame_end_update_cdf: false + base_qindex: 217 + separate_uv_delta_q: true + delta_q_y_dc: 0 + delta_q_u_dc: 0 + delta_q_u_ac: 0 + delta_q_v_dc: 0 + delta_q_v_ac: 0 + using_qmatrix: false + qm_y: 0 + qm_u: 0 + qm_v: 0 + order_hint: 0 + filter_level: 46 + filter_level: 41 + filter_level_u: 20 + filter_level_v: 16 + sharpness_level: 0 + loop_filter_delta_enabled: true + loop_filter_delta_update: true + update_ref_delta: false + loop_filter_ref_deltas: 0 + loop_filter_ref_deltas: 0 + loop_filter_ref_deltas: 0 + loop_filter_ref_deltas: 0 + loop_filter_ref_deltas: 0 + loop_filter_ref_deltas: 0 + loop_filter_ref_deltas: 0 + loop_filter_ref_deltas: 0 + update_mode_delta: false + loop_filter_mode_deltas: 0 + loop_filter_mode_deltas: 0 + delta_lf_present: false + delta_lf_res: 0 + delta_lf_multi: false + delta_q_present: false + delta_q_res: 0 + primary_ref_frame: 0 + ref_frame_idx: 0 + ref_frame_idx: 0 + ref_frame_idx: 0 + ref_frame_idx: 0 + ref_frame_idx: 0 + ref_frame_idx: 0 + ref_frame_idx: 0 + refresh_frame_flags: 0 + ref_order_hint: 0 + ref_order_hint: 0 + ref_order_hint: 0 + ref_order_hint: 0 + ref_order_hint: 0 + ref_order_hint: 0 + ref_order_hint: 0 + ref_order_hint: 0 + cdef_damping_minus_3: 3 + cdef_bits: 0 + cdef_y_pri_strength: 13 + cdef_y_pri_strength: 0 + cdef_y_pri_strength: 0 + cdef_y_pri_strength: 0 + cdef_y_pri_strength: 0 + cdef_y_pri_strength: 0 + cdef_y_pri_strength: 0 + cdef_y_pri_strength: 0 + cdef_y_sec_strength: 3 + cdef_y_sec_strength: 0 + cdef_y_sec_strength: 0 + cdef_y_sec_strength: 0 + cdef_y_sec_strength: 0 + cdef_y_sec_strength: 0 + cdef_y_sec_strength: 0 + cdef_y_sec_strength: 0 + cdef_uv_pri_strength: 5 + cdef_uv_pri_strength: 0 + cdef_uv_pri_strength: 0 + cdef_uv_pri_strength: 0 + cdef_uv_pri_strength: 0 + cdef_uv_pri_strength: 0 + cdef_uv_pri_strength: 0 + cdef_uv_pri_strength: 0 + cdef_uv_sec_strength: 2 + cdef_uv_sec_strength: 0 + cdef_uv_sec_strength: 0 + cdef_uv_sec_strength: 0 + cdef_uv_sec_strength: 0 + cdef_uv_sec_strength: 0 + cdef_uv_sec_strength: 0 + cdef_uv_sec_strength: 0 + restoration_type: 1 + restoration_type: 0 + restoration_type: 0 + lr_unit_shift: 1 + lr_uv_shift: 0 + tx_mode: 1 + reduced_tx_set: false + segmentation_enabled: false + segmentation_update_map: false + segmentation_temporal_update: false + segmentation_update_data: false + segment_number: 0 + feature_data: 0 + allow_screen_content_tools: false + allow_intrabc: false + reference_select: false + } +} \ No newline at end of file
diff --git a/net/data/ssl/chrome_root_store/additional.certs b/net/data/ssl/chrome_root_store/additional.certs index 441ffcf6..5008efb 100644 --- a/net/data/ssl/chrome_root_store/additional.certs +++ b/net/data/ssl/chrome_root_store/additional.certs
@@ -4621,1040 +4621,3 @@ zJfmxHioB7EtWB8BOTY9ZFJZXGDNZqqM0IrIHDsbUJLwPeFJOrFCUVwVcscwh5FI c2IYWCY6wNpb4E8FkrY= -----END CERTIFICATE----- - -SHA-256 hash: b10b6f00e609509e8700f6d34687a2bfce38ea05a8fdf1cdc40c3a2a0d0d0e45 -Subject: "CN=WR1, O=Google Trust Services, C=US" -Issuer: "CN=GTS Root R1, O=Google Trust Services LLC, C=US" -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 7f:d9:e2:c2:d2:04:8a:04:74:b6:27:a2:6d:08:68:a7 - Signature Algorithm: sha256WithRSAEncryption - Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R1 - Validity - Not Before: Dec 13 09:00:00 2023 GMT - Not After : Feb 20 14:00:00 2029 GMT - Subject: C=US, O=Google Trust Services, CN=WR1 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (2048 bit) - Modulus: - 00:cf:6e:36:16:8a:b7:2b:ee:46:98:03:1d:53:70: - 0f:77:ee:a3:4b:a0:72:be:8f:23:2d:c2:47:c6:8f: - 5c:8d:f9:3d:e6:1a:8e:ee:33:22:0d:c9:11:48:b8: - b0:62:ce:f4:69:0d:72:02:7d:de:d5:26:0f:c3:6e: - 9b:cf:7e:0e:d7:20:cf:c6:90:3b:a3:82:06:da:3a: - 9d:ff:6c:56:bf:dc:e9:61:94:45:e4:69:bc:4f:0f: - c9:13:c0:ad:61:44:72:20:81:d0:0f:2b:9e:68:6a: - 62:6a:8f:8a:22:57:79:69:2b:e2:24:33:7e:76:63: - 2c:5d:bc:51:69:7e:23:07:b1:ff:76:81:f1:ee:b8: - 58:b5:6b:35:15:ef:a1:e6:48:28:39:97:31:d9:07: - 1f:95:a7:9e:ae:cf:98:bc:9e:8d:8a:03:e1:b0:97: - 4d:50:6f:93:4c:4a:1f:f8:db:7d:f1:90:99:15:7f: - e3:96:ed:ee:31:81:ea:72:3d:52:1d:df:25:64:a5: - 0b:70:aa:9e:e8:a8:b9:47:c8:a7:5a:10:25:60:6f: - 42:e1:d7:3f:e7:8f:0c:f0:c2:83:46:33:20:e6:4b: - 77:04:76:a1:68:a7:5d:15:18:ef:d8:28:77:35:ad: - 0e:ad:46:e4:62:6e:e2:aa:f8:cc:ef:37:7e:0f:26: - b3:07 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Extended Key Usage: - TLS Web Server Authentication, TLS Web Client Authentication - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:0 - X509v3 Subject Key Identifier: - 66:69:49:D4:DE:2A:9C:91:03:CF:89:0E:24:B8:0E:30:03:6E:88:2E - X509v3 Authority Key Identifier: - keyid:E4:AF:2B:26:71:1A:2B:48:27:85:2F:52:66:2C:EF:F0:89:13:71:3E - - Authority Information Access: - CA Issuers - URI:http://i.pki.goog/r1.crt - - X509v3 CRL Distribution Points: - - Full Name: - URI:http://c.pki.goog/r/r1.crl - - X509v3 Certificate Policies: - Policy: 2.23.140.1.2.1 - - Signature Algorithm: sha256WithRSAEncryption - 4e:e6:b3:08:11:20:91:60:27:f9:51:90:4d:02:18:ee:b8:c1: - 89:d5:22:84:97:e6:d6:df:e6:4e:3a:3b:29:04:7e:de:20:f1: - e2:8d:8b:d3:aa:1e:17:44:37:c2:92:98:a5:08:08:fd:37:8c: - a9:49:58:31:64:26:65:b5:8f:13:43:d7:f2:97:ec:54:01:39: - 13:9b:55:3a:38:77:e1:b3:40:27:00:cf:56:7b:19:54:9c:33: - 37:79:f0:e4:11:90:ee:cc:51:b2:91:73:21:c3:3f:a9:b6:d3: - a4:d7:97:7f:d2:08:e1:6b:24:db:e4:ef:e8:54:95:15:95:0b: - df:fd:2e:1e:b6:9d:6e:bb:83:5a:34:50:e0:86:7b:99:8a:8a: - 88:4a:a4:d3:c7:69:39:9f:93:98:1c:f0:ca:41:06:cb:5f:c8: - 5d:b7:ab:6f:a0:29:d5:24:a7:9f:6f:91:23:bb:7a:37:f7:ea: - 3c:2a:f0:c0:58:e9:f2:48:35:1b:a7:ad:44:04:c6:05:a3:d8: - 0b:1f:86:8c:93:05:3d:7f:a4:f7:b0:25:be:88:f7:ff:df:12: - be:a7:5e:80:b3:d8:10:f8:ef:c5:47:25:1e:98:8a:2c:3e:b7: - 34:c9:95:6a:b5:50:75:d2:0b:ea:43:af:4d:ee:64:d2:99:f1: - 46:74:7e:9a:77:46:1c:84:1c:ef:b4:cb:6d:c6:45:7a:36:b9: - e8:fc:a7:95:2a:a6:7a:be:7b:f1:ce:c2:06:b3:ea:a3:50:55: - 98:fc:96:50:af:af:ea:c1:ae:ce:ce:cc:ab:b4:10:6b:15:6c: - e3:bd:74:70:8f:cc:a4:fa:75:a2:fc:4c:56:dd:7b:10:d2:b1: - 2e:4d:f8:2e:91:0a:00:a5:66:ab:09:f3:6c:71:d1:8e:15:cd: - 78:20:bd:f3:85:c3:3b:02:c4:a7:42:b8:33:31:e5:f1:93:96: - 25:00:1a:90:27:55:94:50:be:3f:20:37:18:fd:89:5f:f4:0b: - a2:a5:8d:1c:6b:8d:f5:cf:6f:2c:e6:c3:84:75:6c:fc:bf:ba: - e4:37:be:39:d9:e7:8e:91:46:23:dc:71:b6:c3:72:46:cc:9a: - 1d:d1:40:7f:9c:fb:ba:53:a8:5c:35:e4:1c:20:9e:8f:f1:21: - b3:97:68:71:17:8d:b7:5e:96:db:16:c7:fc:40:6e:8a:b2:6b: - 3b:31:44:da:bb:40:2f:19:2c:97:54:dd:12:33:9f:20:a5:ce: - 25:f5:2a:41:e5:48:e7:e8:40:ed:5f:a7:d7:e0:3f:9f:b3:69: - 83:44:be:e4:e0:f2:b5:68:79:5d:6e:78:71:c3:75:76:b2:67: - 30:ae:78:b6:da:33:87:47 ------BEGIN CERTIFICATE----- -MIIFCzCCAvOgAwIBAgIQf9niwtIEigR0tieibQhopzANBgkqhkiG9w0BAQsFADBH -MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM -QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMjMxMjEzMDkwMDAwWhcNMjkwMjIw -MTQwMDAwWjA7MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNl -cnZpY2VzMQwwCgYDVQQDEwNXUjEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQDPbjYWircr7kaYAx1TcA937qNLoHK+jyMtwkfGj1yN+T3mGo7uMyINyRFI -uLBizvRpDXICfd7VJg/DbpvPfg7XIM/GkDujggbaOp3/bFa/3OlhlEXkabxPD8kT -wK1hRHIggdAPK55oamJqj4oiV3lpK+IkM352YyxdvFFpfiMHsf92gfHuuFi1azUV -76HmSCg5lzHZBx+Vp56uz5i8no2KA+Gwl01Qb5NMSh/4233xkJkVf+OW7e4xgepy -PVId3yVkpQtwqp7oqLlHyKdaECVgb0Lh1z/njwzwwoNGMyDmS3cEdqFop10VGO/Y -KHc1rQ6tRuRibuKq+MzvN34PJrMHAgMBAAGjgf4wgfswDgYDVR0PAQH/BAQDAgGG -MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/ -AgEAMB0GA1UdDgQWBBRmaUnU3iqckQPPiQ4kuA4wA26ILjAfBgNVHSMEGDAWgBTk -rysmcRorSCeFL1JmLO/wiRNxPjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAKG -GGh0dHA6Ly9pLnBraS5nb29nL3IxLmNydDArBgNVHR8EJDAiMCCgHqAchhpodHRw -Oi8vYy5wa2kuZ29vZy9yL3IxLmNybDATBgNVHSAEDDAKMAgGBmeBDAECATANBgkq -hkiG9w0BAQsFAAOCAgEATuazCBEgkWAn+VGQTQIY7rjBidUihJfm1t/mTjo7KQR+ -3iDx4o2L06oeF0Q3wpKYpQgI/TeMqUlYMWQmZbWPE0PX8pfsVAE5E5tVOjh34bNA -JwDPVnsZVJwzN3nw5BGQ7sxRspFzIcM/qbbTpNeXf9II4Wsk2+Tv6FSVFZUL3/0u -HradbruDWjRQ4IZ7mYqKiEqk08dpOZ+TmBzwykEGy1/IXberb6Ap1SSnn2+RI7t6 -N/fqPCrwwFjp8kg1G6etRATGBaPYCx+GjJMFPX+k97Alvoj3/98SvqdegLPYEPjv -xUclHpiKLD63NMmVarVQddIL6kOvTe5k0pnxRnR+mndGHIQc77TLbcZFeja56Pyn -lSqmer578c7CBrPqo1BVmPyWUK+v6sGuzs7Mq7QQaxVs4710cI/MpPp1ovxMVt17 -ENKxLk34LpEKAKVmqwnzbHHRjhXNeCC984XDOwLEp0K4MzHl8ZOWJQAakCdVlFC+ -PyA3GP2JX/QLoqWNHGuN9c9vLObDhHVs/L+65De+OdnnjpFGI9xxtsNyRsyaHdFA -f5z7ulOoXDXkHCCej/Ehs5docReNt16W2xbH/EBuirJrOzFE2rtALxksl1TdEjOf -IKXOJfUqQeVI5+hA7V+n1+A/n7Npg0S+5ODytWh5XW54ccN1drJnMK54ttozh0c= ------END CERTIFICATE----- - -SHA-256 hash: e6fe22bf45e4f0d3b85c59e02c0f495418e1eb8d3210f788d48cd5e1cb547cd4 -Subject: "CN=WR2, O=Google Trust Services, C=US" -Issuer: "CN=GTS Root R1, O=Google Trust Services LLC, C=US" -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 7f:f0:05:a0:7c:4c:de:d1:00:ad:9d:66:a5:10:7b:98 - Signature Algorithm: sha256WithRSAEncryption - Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R1 - Validity - Not Before: Dec 13 09:00:00 2023 GMT - Not After : Feb 20 14:00:00 2029 GMT - Subject: C=US, O=Google Trust Services, CN=WR2 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (2048 bit) - Modulus: - 00:a9:ff:9c:7f:45:1e:70:a8:53:9f:ca:d9:e5:0d: - de:46:57:57:7d:bc:8f:9a:5a:ac:46:f1:84:9a:bb: - 91:db:c9:fb:2f:01:fb:92:09:00:16:5e:a0:1c:f8: - c1:ab:f9:78:2f:4a:cc:d8:85:a2:d8:59:3c:0e:d3: - 18:fb:b1:f5:24:0d:26:ee:b6:5b:64:76:7c:14:c7: - 2f:7a:ce:a8:4c:b7:f4:d9:08:fc:df:87:23:35:20: - a8:e2:69:e2:8c:4e:3f:b1:59:fa:60:a2:1e:b3:c9: - 20:53:19:82:ca:36:53:6d:60:4d:e9:00:91:fc:76: - 8d:5c:08:0f:0a:c2:dc:f1:73:6b:c5:13:6e:0a:4f: - 7a:c2:f2:02:1c:2e:b4:63:83:da:31:f6:2d:75:30: - b2:fb:ab:c2:6e:db:a9:c0:0e:b9:f9:67:d4:c3:25: - 57:74:eb:05:b4:e9:8e:b5:de:28:cd:cc:7a:14:e4: - 71:03:cb:4d:61:2e:61:57:c5:19:a9:0b:98:84:1a: - e8:79:29:d9:b2:8d:2f:ff:57:6a:66:e0:ce:ab:95: - a8:29:96:63:70:12:67:1e:3a:e1:db:b0:21:71:d7: - 7c:9e:fd:aa:17:6e:fe:2b:fb:38:17:14:d1:66:a7: - af:9a:b5:70:cc:c8:63:81:3a:8c:c0:2a:a9:76:37: - ce:e3 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Extended Key Usage: - TLS Web Server Authentication, TLS Web Client Authentication - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:0 - X509v3 Subject Key Identifier: - DE:1B:1E:ED:79:15:D4:3E:37:24:C3:21:BB:EC:34:39:6D:42:B2:30 - X509v3 Authority Key Identifier: - keyid:E4:AF:2B:26:71:1A:2B:48:27:85:2F:52:66:2C:EF:F0:89:13:71:3E - - Authority Information Access: - CA Issuers - URI:http://i.pki.goog/r1.crt - - X509v3 CRL Distribution Points: - - Full Name: - URI:http://c.pki.goog/r/r1.crl - - X509v3 Certificate Policies: - Policy: 2.23.140.1.2.1 - - Signature Algorithm: sha256WithRSAEncryption - 45:75:8b:e5:1f:3b:44:13:96:1a:ab:58:f1:35:c9:6f:3d:d2: - d0:33:4a:86:33:ba:57:51:4f:ee:c4:34:da:16:12:4c:bf:13: - 9f:0d:d4:54:e9:48:79:c0:30:3c:94:25:f2:1a:f4:ba:32:94: - b6:33:72:0b:85:ee:09:11:25:34:94:e1:6f:42:db:82:9b:7b: - 7f:2a:9a:a9:ff:7f:a9:d2:de:4a:20:cb:b3:fb:03:03:b8:f8: - 07:05:da:59:92:2f:18:46:98:ce:af:72:be:24:26:b1:1e:00: - 4d:bd:08:ad:93:41:44:0a:bb:c7:d5:01:85:bf:93:57:e3:df: - 74:12:53:0e:11:25:d3:9b:dc:de:cb:27:6e:b3:c2:b9:33:62: - 39:c2:e0:35:e1:5b:a7:09:2e:19:cb:91:2a:76:5c:f1:df:ca: - 23:84:40:a5:6f:ff:9a:41:e0:b5:ef:32:d1:85:ae:af:25:09: - f0:62:c5:6e:c2:c8:6e:32:fd:b8:da:e2:ce:4a:91:4a:f3:85: - 55:4e:b1:75:d6:48:33:2f:6f:84:d9:12:5c:9f:d4:71:98:63: - 25:8d:69:5c:0a:6b:7d:f2:41:bd:e8:bb:8f:e4:22:d7:9d:65: - 45:e8:4c:0a:87:da:e9:60:66:88:0e:1f:c7:e1:4e:56:c5:76: - ff:b4:7a:57:69:f2:02:22:09:26:41:1d:da:74:a2:e5:29:f3: - c4:9a:e5:5d:d6:aa:7a:fd:e1:b7:2b:66:38:fb:e8:29:66:ba: - ef:a0:13:2f:f8:73:7e:f0:da:40:11:1c:5d:dd:8f:a6:fc:be: - db:be:56:f8:32:9c:1f:41:41:6d:7e:b6:c5:eb:c6:8b:36:b7: - 17:8c:9d:cf:19:7a:34:9f:21:93:c4:7e:74:35:d2:aa:fd:4c: - 6d:14:f5:c9:b0:79:5b:49:3c:f3:bf:17:48:e8:ef:9a:26:13: - 0c:87:f2:73:d6:9c:c5:52:6b:63:f7:32:90:78:a9:6b:eb:5e: - d6:93:a1:bf:bc:18:3d:8b:59:f6:8a:c6:05:5e:52:18:e2:66: - e0:da:c1:dc:ad:5a:25:aa:f4:45:fc:f1:0b:78:a4:af:b0:f2: - 73:a4:30:a8:34:c1:53:7f:42:96:e5:48:41:eb:90:46:0c:06: - dc:cb:92:c6:5e:f3:44:44:43:46:29:46:a0:a6:fc:b9:8e:39: - 27:39:b1:5a:e2:b1:ad:fc:13:ff:8e:fc:26:e1:d4:fe:84:f1: - 50:5a:8e:97:6b:2d:2a:79:fb:40:64:ea:f3:3d:bd:5b:e1:a0: - 04:b0:97:48:1c:42:f5:ea:5a:1c:cd:26:c8:51:ff:14:99:67: - 89:72:5f:1d:ec:ad:5a:dd ------BEGIN CERTIFICATE----- -MIIFCzCCAvOgAwIBAgIQf/AFoHxM3tEArZ1mpRB7mDANBgkqhkiG9w0BAQsFADBH -MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM -QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMjMxMjEzMDkwMDAwWhcNMjkwMjIw -MTQwMDAwWjA7MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNl -cnZpY2VzMQwwCgYDVQQDEwNXUjIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQCp/5x/RR5wqFOfytnlDd5GV1d9vI+aWqxG8YSau5HbyfsvAfuSCQAWXqAc -+MGr+XgvSszYhaLYWTwO0xj7sfUkDSbutltkdnwUxy96zqhMt/TZCPzfhyM1IKji -aeKMTj+xWfpgoh6zySBTGYLKNlNtYE3pAJH8do1cCA8Kwtzxc2vFE24KT3rC8gIc -LrRjg9ox9i11MLL7q8Ju26nADrn5Z9TDJVd06wW06Y613ijNzHoU5HEDy01hLmFX -xRmpC5iEGuh5KdmyjS//V2pm4M6rlagplmNwEmceOuHbsCFx13ye/aoXbv4r+zgX -FNFmp6+atXDMyGOBOozAKql2N87jAgMBAAGjgf4wgfswDgYDVR0PAQH/BAQDAgGG -MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/ -AgEAMB0GA1UdDgQWBBTeGx7teRXUPjckwyG77DQ5bUKyMDAfBgNVHSMEGDAWgBTk -rysmcRorSCeFL1JmLO/wiRNxPjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAKG -GGh0dHA6Ly9pLnBraS5nb29nL3IxLmNydDArBgNVHR8EJDAiMCCgHqAchhpodHRw -Oi8vYy5wa2kuZ29vZy9yL3IxLmNybDATBgNVHSAEDDAKMAgGBmeBDAECATANBgkq -hkiG9w0BAQsFAAOCAgEARXWL5R87RBOWGqtY8TXJbz3S0DNKhjO6V1FP7sQ02hYS -TL8Tnw3UVOlIecAwPJQl8hr0ujKUtjNyC4XuCRElNJThb0Lbgpt7fyqaqf9/qdLe -SiDLs/sDA7j4BwXaWZIvGEaYzq9yviQmsR4ATb0IrZNBRAq7x9UBhb+TV+PfdBJT -DhEl05vc3ssnbrPCuTNiOcLgNeFbpwkuGcuRKnZc8d/KI4RApW//mkHgte8y0YWu -ryUJ8GLFbsLIbjL9uNrizkqRSvOFVU6xddZIMy9vhNkSXJ/UcZhjJY1pXAprffJB -vei7j+Qi151lRehMCofa6WBmiA4fx+FOVsV2/7R6V2nyAiIJJkEd2nSi5SnzxJrl -Xdaqev3htytmOPvoKWa676ATL/hzfvDaQBEcXd2Ppvy+275W+DKcH0FBbX62xevG -iza3F4ydzxl6NJ8hk8R+dDXSqv1MbRT1ybB5W0k8878XSOjvmiYTDIfyc9acxVJr -Y/cykHipa+te1pOhv7wYPYtZ9orGBV5SGOJm4NrB3K1aJar0RfzxC3ikr7Dyc6Qw -qDTBU39CluVIQeuQRgwG3MuSxl7zRERDRilGoKb8uY45JzmxWuKxrfwT/478JuHU -/oTxUFqOl2stKnn7QGTq8z29W+GgBLCXSBxC9epaHM0myFH/FJlniXJfHeytWt0= ------END CERTIFICATE----- - -SHA-256 hash: 2fe357db13751ff9160e87354975b3407498f41c9bd16a48657866e6e5a9b4c7 -Subject: "CN=WR3, O=Google Trust Services, C=US" -Issuer: "CN=GTS Root R1, O=Google Trust Services LLC, C=US" -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 7f:f0:05:a9:15:68:d6:3a:bc:22:86:16:84:aa:4b:5a - Signature Algorithm: sha256WithRSAEncryption - Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R1 - Validity - Not Before: Dec 13 09:00:00 2023 GMT - Not After : Feb 20 14:00:00 2029 GMT - Subject: C=US, O=Google Trust Services, CN=WR3 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (2048 bit) - Modulus: - 00:8f:34:75:87:af:84:72:14:8d:07:10:91:6f:03: - ac:f1:d4:08:35:9a:19:f2:9b:18:89:34:6c:98:8f: - 7a:d4:dd:ea:05:e8:de:1b:7c:8c:54:12:ba:79:8a: - fb:18:0d:0d:7c:9c:f3:bd:38:e4:a8:5e:c6:33:cb: - 46:89:6f:46:a0:e9:37:63:8d:dc:cc:d5:97:4e:32: - ad:7b:1d:23:05:b9:f5:7b:49:43:98:d0:bc:57:c7: - 53:78:18:b1:ed:a7:54:b2:7c:86:be:f0:54:45:bc: - 87:ba:99:59:1d:f4:b8:db:00:fb:81:4f:46:2b:62: - 5e:b1:3a:a5:2a:17:23:ac:a2:be:c5:8e:e5:5e:fd: - 71:1e:7d:a4:b4:23:7d:04:52:b2:34:d2:df:99:ac: - 87:c6:4c:59:5f:f8:e6:4f:8e:75:92:c2:b2:30:46: - 92:d0:b6:0d:c7:e4:89:67:ff:3f:54:94:27:65:e3: - 01:c8:4a:2c:84:2f:65:5f:cd:ad:5c:fd:a6:ad:41: - 5b:dc:4c:3f:17:96:91:7d:a9:d8:3c:53:2a:1c:d0: - e6:d4:77:e6:43:4a:c2:b7:f8:48:a2:cd:ad:63:b5: - 25:6b:96:72:1d:81:45:6f:86:69:c4:e4:e6:78:4c: - 31:e6:a1:7f:a7:01:73:0a:87:ef:87:89:72:cc:d3: - c5:8d - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Extended Key Usage: - TLS Web Server Authentication, TLS Web Client Authentication - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:0 - X509v3 Subject Key Identifier: - C7:81:F5:FD:8E:88:D9:00:3C:4D:63:A2:50:31:24:A0:CE:23:FE:23 - X509v3 Authority Key Identifier: - keyid:E4:AF:2B:26:71:1A:2B:48:27:85:2F:52:66:2C:EF:F0:89:13:71:3E - - Authority Information Access: - CA Issuers - URI:http://i.pki.goog/r1.crt - - X509v3 CRL Distribution Points: - - Full Name: - URI:http://c.pki.goog/r/r1.crl - - X509v3 Certificate Policies: - Policy: 2.23.140.1.2.1 - - Signature Algorithm: sha256WithRSAEncryption - 9c:8d:43:94:94:33:48:a7:16:6f:25:d7:ac:94:ac:80:a3:28: - e8:a1:bb:e1:33:2a:86:cb:93:83:ae:da:d0:55:f4:db:be:76: - f9:e8:89:6f:96:2c:38:97:3c:0d:53:87:6a:5c:29:3a:f6:ee: - 3d:d9:79:06:e0:04:80:82:b8:55:ae:e5:f6:3d:c9:f4:cd:7f: - 12:37:96:8c:64:cc:dd:1a:2c:ce:60:49:1a:ef:36:a3:3e:84: - 5a:2e:6a:ef:9c:5e:17:ea:27:26:68:76:1e:6f:7c:6b:fc:89: - 00:8f:e6:38:35:ea:e4:ba:1f:61:c4:3d:01:f7:ca:3f:d6:4c: - 66:ef:98:c1:6f:bf:a8:7a:b2:5f:62:61:68:e9:ed:be:5e:e2: - f1:2f:a5:d5:8f:02:70:a1:2a:33:53:45:2b:8b:38:10:16:0f: - 44:58:d9:0d:ac:0e:1d:7e:df:49:c8:5b:48:c5:4f:9f:93:6e: - d3:89:6b:53:ac:6e:7e:e6:6a:46:8b:04:43:0d:a8:d1:40:32: - cc:3a:32:03:9d:8d:5f:32:53:5a:bd:46:d8:55:60:ff:40:3d: - 85:da:d0:ff:a7:de:f4:6d:f5:eb:bc:ca:c4:da:97:12:bb:3a: - 32:91:ed:b4:4a:2e:19:ba:66:d9:fb:73:ae:67:2f:ae:e6:31: - 4d:fc:5c:e0:6d:86:c0:18:b7:2c:52:e8:cc:da:72:d3:8d:a0: - 0d:f5:c1:cc:3c:a7:d6:cb:5a:5a:cc:bb:f9:09:f3:32:54:79: - f4:5c:fa:8c:13:a4:e5:1e:0b:4f:e9:9a:d3:e2:a3:9d:f4:61: - 32:1e:53:da:e7:26:eb:d1:e4:bc:d4:2d:0d:99:55:6b:5b:4b: - 52:5c:ec:d3:32:c4:75:04:9e:85:30:a3:67:a4:98:b0:6b:76: - 6c:c5:4a:e9:db:ed:c7:37:32:08:fd:10:0d:41:67:35:70:b0: - 83:0d:76:fa:61:92:90:0b:a3:e0:e4:62:f2:43:11:a6:72:fc: - 50:48:e4:35:b7:70:f4:a2:f5:79:86:c4:0b:70:f4:18:fb:9e: - d9:89:36:00:68:71:92:67:1d:9b:50:68:3a:9d:39:91:8c:3f: - 36:7a:a0:87:b4:15:f0:32:b2:05:35:07:6e:31:f4:a5:79:4b: - 88:eb:12:39:8f:82:2e:1d:5e:4c:cf:83:a3:aa:d2:8e:a1:a7: - 0d:07:94:5f:29:59:98:f0:a6:ba:f7:9a:c3:7f:08:56:70:5a: - 6b:a1:22:cf:aa:67:81:9d:6e:e8:e7:8e:ff:55:33:7e:19:b2: - 4e:6d:27:d0:6f:bd:25:9d:ca:4b:63:2a:d3:c8:ac:36:05:c7: - 2e:78:65:1c:96:a9:86:91 ------BEGIN CERTIFICATE----- -MIIFCzCCAvOgAwIBAgIQf/AFqRVo1jq8IoYWhKpLWjANBgkqhkiG9w0BAQsFADBH -MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM -QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMjMxMjEzMDkwMDAwWhcNMjkwMjIw -MTQwMDAwWjA7MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNl -cnZpY2VzMQwwCgYDVQQDEwNXUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQCPNHWHr4RyFI0HEJFvA6zx1Ag1mhnymxiJNGyYj3rU3eoF6N4bfIxUErp5 -ivsYDQ18nPO9OOSoXsYzy0aJb0ag6TdjjdzM1ZdOMq17HSMFufV7SUOY0LxXx1N4 -GLHtp1SyfIa+8FRFvIe6mVkd9LjbAPuBT0YrYl6xOqUqFyOsor7FjuVe/XEefaS0 -I30EUrI00t+ZrIfGTFlf+OZPjnWSwrIwRpLQtg3H5Iln/z9UlCdl4wHISiyEL2Vf -za1c/aatQVvcTD8XlpF9qdg8Uyoc0ObUd+ZDSsK3+Eiiza1jtSVrlnIdgUVvhmnE -5OZ4TDHmoX+nAXMKh++HiXLM08WNAgMBAAGjgf4wgfswDgYDVR0PAQH/BAQDAgGG -MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/ -AgEAMB0GA1UdDgQWBBTHgfX9jojZADxNY6JQMSSgziP+IzAfBgNVHSMEGDAWgBTk -rysmcRorSCeFL1JmLO/wiRNxPjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAKG -GGh0dHA6Ly9pLnBraS5nb29nL3IxLmNydDArBgNVHR8EJDAiMCCgHqAchhpodHRw -Oi8vYy5wa2kuZ29vZy9yL3IxLmNybDATBgNVHSAEDDAKMAgGBmeBDAECATANBgkq -hkiG9w0BAQsFAAOCAgEAnI1DlJQzSKcWbyXXrJSsgKMo6KG74TMqhsuTg67a0FX0 -2752+eiJb5YsOJc8DVOHalwpOvbuPdl5BuAEgIK4Va7l9j3J9M1/EjeWjGTM3Ros -zmBJGu82oz6EWi5q75xeF+onJmh2Hm98a/yJAI/mODXq5LofYcQ9AffKP9ZMZu+Y -wW+/qHqyX2JhaOntvl7i8S+l1Y8CcKEqM1NFK4s4EBYPRFjZDawOHX7fSchbSMVP -n5Nu04lrU6xufuZqRosEQw2o0UAyzDoyA52NXzJTWr1G2FVg/0A9hdrQ/6fe9G31 -67zKxNqXErs6MpHttEouGbpm2ftzrmcvruYxTfxc4G2GwBi3LFLozNpy042gDfXB -zDyn1staWsy7+QnzMlR59Fz6jBOk5R4LT+ma0+KjnfRhMh5T2ucm69HkvNQtDZlV -a1tLUlzs0zLEdQSehTCjZ6SYsGt2bMVK6dvtxzcyCP0QDUFnNXCwgw12+mGSkAuj -4ORi8kMRpnL8UEjkNbdw9KL1eYbEC3D0GPue2Yk2AGhxkmcdm1BoOp05kYw/Nnqg -h7QV8DKyBTUHbjH0pXlLiOsSOY+CLh1eTM+Do6rSjqGnDQeUXylZmPCmuveaw38I -VnBaa6Eiz6pngZ1u6OeO/1UzfhmyTm0n0G+9JZ3KS2Mq08isNgXHLnhlHJaphpE= ------END CERTIFICATE----- - -SHA-256 hash: dc9416c2f855126d6de977677538f2f967ff4998e90dfa435a17219be077fc06 -Subject: "CN=WR4, O=Google Trust Services, C=US" -Issuer: "CN=GTS Root R1, O=Google Trust Services LLC, C=US" -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 7f:f0:05:b4:da:75:b8:6a:5a:c6:1f:e4:30:77:13:cd - Signature Algorithm: sha256WithRSAEncryption - Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R1 - Validity - Not Before: Dec 13 09:00:00 2023 GMT - Not After : Feb 20 14:00:00 2029 GMT - Subject: C=US, O=Google Trust Services, CN=WR4 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (2048 bit) - Modulus: - 00:af:4e:51:bf:ce:50:a4:eb:8e:3d:91:a5:bf:0c: - 2a:22:aa:8a:74:a4:8c:32:68:df:0a:40:66:ec:57: - 6d:2c:af:46:f8:db:d2:6b:44:c4:0b:25:3f:fb:b0: - 84:4b:b1:77:6b:55:c0:39:ef:be:55:f5:74:3f:16: - 55:4f:52:cc:85:41:a5:87:13:18:1a:41:a7:f6:3d: - 9c:4d:56:46:1f:4f:d4:93:e7:b6:bd:51:b5:7e:35: - 39:5d:72:79:b1:be:8a:0b:9a:98:70:fd:31:6f:96: - 7a:6a:da:b3:35:e7:29:47:8a:af:25:1a:a8:10:a5: - 1f:7f:e8:02:ee:a2:59:96:0d:53:8f:14:48:00:95: - 37:7d:42:81:16:f6:02:cc:b8:6d:e5:3b:7d:65:b6: - c7:a7:65:64:f5:94:24:12:d9:14:55:4b:15:e3:ed: - c4:77:da:55:e0:48:4b:24:d5:9c:f9:ed:e4:65:80: - 27:f2:7c:0b:d4:25:4b:4c:b7:df:36:b2:83:51:d9: - dc:ce:54:e2:a3:f7:39:62:78:5a:db:75:f0:59:87: - 16:47:42:7e:c8:26:e1:9c:71:d8:89:9c:a4:d3:79: - b0:63:c4:c8:54:71:41:e4:eb:6c:a5:3b:b8:1e:2e: - d6:f7:24:c5:1b:6e:7b:d2:60:3d:94:01:c9:60:ce: - bc:25 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Extended Key Usage: - TLS Web Server Authentication, TLS Web Client Authentication - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:0 - X509v3 Subject Key Identifier: - 9B:C8:11:BC:3D:AA:36:B9:31:8C:4E:8F:44:D5:57:32:2F:C3:C0:61 - X509v3 Authority Key Identifier: - keyid:E4:AF:2B:26:71:1A:2B:48:27:85:2F:52:66:2C:EF:F0:89:13:71:3E - - Authority Information Access: - CA Issuers - URI:http://i.pki.goog/r1.crt - - X509v3 CRL Distribution Points: - - Full Name: - URI:http://c.pki.goog/r/r1.crl - - X509v3 Certificate Policies: - Policy: 2.23.140.1.2.1 - - Signature Algorithm: sha256WithRSAEncryption - 87:69:c3:f5:60:f9:b2:4c:d4:2c:0c:66:21:db:71:55:96:45: - f3:fe:70:b7:98:9f:20:c5:00:51:13:55:c1:97:0b:f6:eb:8e: - be:b3:53:ef:9a:55:87:2d:d8:e1:da:bd:3e:d0:43:c8:89:a0: - 4d:c2:17:ae:aa:7c:10:b9:50:1d:b3:06:47:6a:27:0b:5c:b9: - 85:18:a8:47:71:86:d4:9f:2a:18:17:b7:07:50:d0:ce:7d:2a: - a3:91:a4:af:1e:22:8a:3f:dd:ea:dc:a8:1b:17:f3:74:0b:ed: - 3d:14:3e:93:a3:da:5d:af:0b:59:d8:63:a5:2f:ff:58:58:0e: - e8:c5:ce:29:ee:aa:4e:27:15:9a:3e:b8:5d:8c:23:a0:34:18: - 36:e6:07:b4:25:8f:16:b5:bc:8a:60:9d:dd:1d:79:1f:ed:ca: - 94:29:cc:ec:5b:d0:c9:d3:6b:d3:82:cf:52:df:cb:60:cf:06: - 64:70:49:c9:4a:b5:a1:7b:c4:e5:12:96:92:8c:35:3e:d1:e9: - ba:6d:fd:f2:e1:b2:57:37:fe:be:ef:b4:d6:2f:e6:74:34:29: - b1:bf:c8:fc:f4:15:f4:10:09:8a:7f:44:d9:c7:d8:2e:50:2c: - 36:5f:55:69:4a:14:8a:0f:6a:ba:54:be:8e:49:dd:86:d3:92: - 41:c5:ad:c3:ad:98:2e:e1:a8:ff:22:3d:70:5e:14:63:8a:bd: - 95:68:0d:3b:b2:fd:21:55:47:42:8f:78:a0:2a:cb:d6:04:4c: - 28:03:6d:16:46:9c:2c:31:02:c0:0b:85:48:ab:ee:85:ae:c3: - 6a:76:3b:85:9e:d8:a8:5e:87:90:d9:49:cd:30:3a:63:d5:11: - 36:af:4c:c6:a2:61:31:e4:dd:91:e7:f3:fa:cd:40:77:f4:18: - d1:ed:8c:1c:68:1b:13:ea:0d:77:86:b0:4d:da:c4:c5:2d:81: - d8:4a:7b:c1:c4:a2:d6:80:37:e2:92:1a:26:04:2e:5a:ef:05: - ae:87:02:b3:3b:2a:73:ea:09:59:3a:f0:d9:54:20:7b:dc:60: - 51:95:0c:64:b4:56:6c:5e:23:dc:52:8f:b1:55:60:57:ee:e0: - f7:94:4d:12:31:a1:0b:53:3c:2d:ab:3c:c3:0e:53:fa:e0:4f: - 30:bb:12:42:4d:81:44:77:30:7f:20:d1:db:4f:76:24:59:5d: - 1a:e0:3c:31:40:2b:18:df:e7:1d:30:df:59:a6:0b:20:f0:94: - 87:00:61:a5:83:a3:2a:78:b8:78:f2:eb:69:da:bb:00:6d:90: - a0:65:6c:cd:9c:20:25:ea:8b:5c:90:5f:f8:8e:a7:cb:31:5d: - d9:ce:4e:5c:c1:ba:e4:d7 ------BEGIN CERTIFICATE----- -MIIFCzCCAvOgAwIBAgIQf/AFtNp1uGpaxh/kMHcTzTANBgkqhkiG9w0BAQsFADBH -MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM -QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMjMxMjEzMDkwMDAwWhcNMjkwMjIw -MTQwMDAwWjA7MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNl -cnZpY2VzMQwwCgYDVQQDEwNXUjQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQCvTlG/zlCk6449kaW/DCoiqop0pIwyaN8KQGbsV20sr0b429JrRMQLJT/7 -sIRLsXdrVcA5775V9XQ/FlVPUsyFQaWHExgaQaf2PZxNVkYfT9ST57a9UbV+NTld -cnmxvooLmphw/TFvlnpq2rM15ylHiq8lGqgQpR9/6ALuolmWDVOPFEgAlTd9QoEW -9gLMuG3lO31ltsenZWT1lCQS2RRVSxXj7cR32lXgSEsk1Zz57eRlgCfyfAvUJUtM -t982soNR2dzOVOKj9zlieFrbdfBZhxZHQn7IJuGccdiJnKTTebBjxMhUcUHk62yl -O7geLtb3JMUbbnvSYD2UAclgzrwlAgMBAAGjgf4wgfswDgYDVR0PAQH/BAQDAgGG -MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/ -AgEAMB0GA1UdDgQWBBSbyBG8Pao2uTGMTo9E1VcyL8PAYTAfBgNVHSMEGDAWgBTk -rysmcRorSCeFL1JmLO/wiRNxPjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAKG -GGh0dHA6Ly9pLnBraS5nb29nL3IxLmNydDArBgNVHR8EJDAiMCCgHqAchhpodHRw -Oi8vYy5wa2kuZ29vZy9yL3IxLmNybDATBgNVHSAEDDAKMAgGBmeBDAECATANBgkq -hkiG9w0BAQsFAAOCAgEAh2nD9WD5skzULAxmIdtxVZZF8/5wt5ifIMUAURNVwZcL -9uuOvrNT75pVhy3Y4dq9PtBDyImgTcIXrqp8ELlQHbMGR2onC1y5hRioR3GG1J8q -GBe3B1DQzn0qo5Gkrx4iij/d6tyoGxfzdAvtPRQ+k6PaXa8LWdhjpS//WFgO6MXO -Ke6qTicVmj64XYwjoDQYNuYHtCWPFrW8imCd3R15H+3KlCnM7FvQydNr04LPUt/L -YM8GZHBJyUq1oXvE5RKWkow1PtHpum398uGyVzf+vu+01i/mdDQpsb/I/PQV9BAJ -in9E2cfYLlAsNl9VaUoUig9qulS+jkndhtOSQcWtw62YLuGo/yI9cF4UY4q9lWgN -O7L9IVVHQo94oCrL1gRMKANtFkacLDECwAuFSKvuha7DanY7hZ7YqF6HkNlJzTA6 -Y9URNq9MxqJhMeTdkefz+s1Ad/QY0e2MHGgbE+oNd4awTdrExS2B2Ep7wcSi1oA3 -4pIaJgQuWu8FrocCszsqc+oJWTrw2VQge9xgUZUMZLRWbF4j3FKPsVVgV+7g95RN -EjGhC1M8Las8ww5T+uBPMLsSQk2BRHcwfyDR2092JFldGuA8MUArGN/nHTDfWaYL -IPCUhwBhpYOjKni4ePLradq7AG2QoGVszZwgJeqLXJBf+I6nyzFd2c5OXMG65Nc= ------END CERTIFICATE----- - -SHA-256 hash: ae0fc852280f1b87cedaf73cfb84cf106efec88e8294253af352ed4034460d7b -Subject: "CN=WR5, O=Google Trust Services, C=US" -Issuer: "CN=GTS Root R2, O=Google Trust Services LLC, C=US" -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 7f:f4:e5:c9:14:96:b0:f2:a1:89:05:ed:50:1e:62:a3 - Signature Algorithm: sha256WithRSAEncryption - Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R2 - Validity - Not Before: Dec 13 09:00:00 2023 GMT - Not After : Feb 20 14:00:00 2029 GMT - Subject: C=US, O=Google Trust Services, CN=WR5 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (2048 bit) - Modulus: - 00:9b:d5:5c:98:85:c1:56:ed:4b:69:4e:a3:73:22: - 2c:ba:b4:e2:64:d2:62:6e:a5:cd:1d:27:2d:4f:77: - be:96:c1:e8:32:9b:e3:d9:6d:09:1e:f0:3f:60:9d: - 81:bd:da:86:2f:c0:62:b7:0c:a4:ed:c8:5c:bc:a9: - 5d:88:c5:60:16:2a:61:0d:5f:19:57:81:4c:13:eb: - 2e:b0:19:f6:e5:db:86:59:18:9b:21:14:3d:e8:fd: - 63:16:13:b6:e8:70:25:d5:4f:95:6f:46:f0:8c:46: - be:b7:23:80:35:90:52:ec:4e:45:0b:24:16:28:6b: - 9b:2e:5c:28:73:00:02:c7:74:2a:30:76:8f:89:ee: - b5:c2:f9:d2:4d:1a:11:d3:ba:f2:72:7f:3f:6a:7b: - 42:3c:6b:bc:a5:0d:b6:b4:16:20:f1:c3:30:12:a7: - 5d:1d:02:b4:99:7f:5b:31:3a:6c:b6:d5:3e:21:a2: - bc:68:93:de:9b:9f:67:36:8b:61:77:3f:17:96:b2: - 45:8b:4e:c9:f1:26:18:c1:eb:73:b0:aa:4b:b4:d6: - 40:bf:43:f1:c1:ca:c9:74:4c:55:3b:cc:54:80:f8: - 30:33:e1:14:c7:cb:bb:05:64:aa:d1:2e:bc:7c:28: - 89:78:83:06:e9:b7:02:48:e3:8b:a1:86:b9:55:a8: - 40:dd - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Extended Key Usage: - TLS Web Server Authentication, TLS Web Client Authentication - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:0 - X509v3 Subject Key Identifier: - 4C:5B:19:C2:8F:1A:7F:55:6F:AA:10:29:FA:02:8B:C7:3C:2A:22:3C - X509v3 Authority Key Identifier: - keyid:BB:FF:CA:8E:23:9F:4F:99:CA:DB:E2:68:A6:A5:15:27:17:1E:D9:0E - - Authority Information Access: - CA Issuers - URI:http://i.pki.goog/r2.crt - - X509v3 CRL Distribution Points: - - Full Name: - URI:http://c.pki.goog/r/r2.crl - - X509v3 Certificate Policies: - Policy: 2.23.140.1.2.1 - - Signature Algorithm: sha256WithRSAEncryption - c1:c0:50:db:85:d8:49:34:e5:9e:84:35:1a:42:3b:89:b6:4c: - 8a:9a:9d:9a:44:3d:d1:4a:68:04:f1:f9:0e:ae:c4:9c:33:07: - 83:3d:bc:f8:06:82:12:3c:c7:1a:0f:38:ab:86:bb:0b:1f:e0: - 5f:e4:67:23:22:a6:a9:6f:4f:3c:00:63:11:87:d0:20:d6:b6: - e1:f0:0c:56:50:ea:e8:ec:14:3e:93:c3:5a:97:30:bf:4f:1b: - d4:a9:6b:5a:dc:ae:17:50:12:3b:1b:5c:e0:81:ed:dc:8b:b1: - be:4e:04:25:79:d1:90:85:41:82:2e:eb:b0:39:4a:a2:41:f5: - b0:70:a1:26:7b:0f:14:7e:03:ce:d5:46:dd:69:d5:38:5b:a3: - cb:a4:ad:48:43:1a:11:75:b1:8a:a7:f3:53:ee:14:e1:84:e0: - 7d:3a:e4:55:ec:59:18:74:5b:99:75:3e:4b:91:62:e9:53:f0: - 18:5b:cd:44:09:3c:82:8c:5c:bf:3a:c6:7a:87:c0:04:0a:4a: - a5:4d:43:aa:5f:9e:a8:b4:68:6c:90:07:51:ee:74:d1:57:d5: - 55:62:e2:7a:bd:8c:46:8c:4a:1e:7f:b2:ac:3b:77:14:6e:80: - 25:63:0f:92:e4:72:08:99:2e:7f:0a:02:39:0d:97:14:0c:92: - 68:c8:78:45:00:31:75:61:59:a9:51:a9:aa:8b:3b:37:ab:4c: - 76:f5:4f:cf:b4:ec:d3:87:18:54:13:ab:84:76:0e:74:5d:ba: - c8:80:c6:6f:f6:dc:8f:ba:50:7a:e8:51:81:8a:7e:b2:a6:6a: - fb:43:e8:3f:71:43:6f:07:3e:07:b5:96:d0:c0:6b:b0:a2:af: - 72:b5:7d:ca:0c:e4:47:c6:31:92:d0:3e:1a:6d:d4:25:3c:9c: - 17:45:1b:b3:81:c4:26:fe:a7:1c:16:b2:d0:80:c6:7c:b4:70: - 53:99:01:75:66:84:6e:63:f6:4c:4b:ca:1b:f3:a0:c6:37:09: - 6f:e8:44:a1:52:9d:fa:cb:3a:6e:e2:d7:d5:d7:bf:0e:f5:8c: - 76:31:4f:e5:ad:bb:3d:c0:93:de:0c:75:51:4d:37:76:31:19: - ff:b8:c5:9d:19:f0:39:e3:47:0a:d4:59:4d:79:19:dd:05:07: - 5b:1a:da:3b:d8:ad:e3:6d:06:f7:4d:46:be:8b:37:71:16:de: - 39:b0:94:b5:cb:a5:f7:f5:1b:f4:28:a5:a8:2d:fe:7d:84:be: - a5:0b:bc:ed:83:fc:62:60:a3:ce:86:26:fe:4d:12:c2:d7:e2: - 1c:95:c1:ae:de:6c:7a:05:a4:2b:30:f8:d0:de:46:f7:59:5f: - b6:77:b8:4f:5e:8f:ab:0b ------BEGIN CERTIFICATE----- -MIIFCzCCAvOgAwIBAgIQf/TlyRSWsPKhiQXtUB5iozANBgkqhkiG9w0BAQsFADBH -MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM -QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMjMxMjEzMDkwMDAwWhcNMjkwMjIw -MTQwMDAwWjA7MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNl -cnZpY2VzMQwwCgYDVQQDEwNXUjUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQCb1VyYhcFW7UtpTqNzIiy6tOJk0mJupc0dJy1Pd76Wwegym+PZbQke8D9g -nYG92oYvwGK3DKTtyFy8qV2IxWAWKmENXxlXgUwT6y6wGfbl24ZZGJshFD3o/WMW -E7bocCXVT5VvRvCMRr63I4A1kFLsTkULJBYoa5suXChzAALHdCowdo+J7rXC+dJN -GhHTuvJyfz9qe0I8a7ylDba0FiDxwzASp10dArSZf1sxOmy21T4horxok96bn2c2 -i2F3PxeWskWLTsnxJhjB63Owqku01kC/Q/HBysl0TFU7zFSA+DAz4RTHy7sFZKrR -Lrx8KIl4gwbptwJI44uhhrlVqEDdAgMBAAGjgf4wgfswDgYDVR0PAQH/BAQDAgGG -MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/ -AgEAMB0GA1UdDgQWBBRMWxnCjxp/VW+qECn6AovHPCoiPDAfBgNVHSMEGDAWgBS7 -/8qOI59Pmcrb4mimpRUnFx7ZDjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAKG -GGh0dHA6Ly9pLnBraS5nb29nL3IyLmNydDArBgNVHR8EJDAiMCCgHqAchhpodHRw -Oi8vYy5wa2kuZ29vZy9yL3IyLmNybDATBgNVHSAEDDAKMAgGBmeBDAECATANBgkq -hkiG9w0BAQsFAAOCAgEAwcBQ24XYSTTlnoQ1GkI7ibZMipqdmkQ90UpoBPH5Dq7E -nDMHgz28+AaCEjzHGg84q4a7Cx/gX+RnIyKmqW9PPABjEYfQINa24fAMVlDq6OwU -PpPDWpcwv08b1KlrWtyuF1ASOxtc4IHt3Iuxvk4EJXnRkIVBgi7rsDlKokH1sHCh -JnsPFH4DztVG3WnVOFujy6StSEMaEXWxiqfzU+4U4YTgfTrkVexZGHRbmXU+S5Fi -6VPwGFvNRAk8goxcvzrGeofABApKpU1Dql+eqLRobJAHUe500VfVVWLier2MRoxK -Hn+yrDt3FG6AJWMPkuRyCJkufwoCOQ2XFAySaMh4RQAxdWFZqVGpqos7N6tMdvVP -z7Ts04cYVBOrhHYOdF26yIDGb/bcj7pQeuhRgYp+sqZq+0PoP3FDbwc+B7WW0MBr -sKKvcrV9ygzkR8YxktA+Gm3UJTycF0Ubs4HEJv6nHBay0IDGfLRwU5kBdWaEbmP2 -TEvKG/OgxjcJb+hEoVKd+ss6buLX1de/DvWMdjFP5a27PcCT3gx1UU03djEZ/7jF -nRnwOeNHCtRZTXkZ3QUHWxraO9it420G901Gvos3cRbeObCUtcul9/Ub9CilqC3+ -fYS+pQu87YP8YmCjzoYm/k0SwtfiHJXBrt5segWkKzD40N5G91lftne4T16Pqws= ------END CERTIFICATE----- - -SHA-256 hash: 1dfc1605fbad358d8bc844f76d15203fac9ca5c1a79fd4857ffaf2864fbebf96 -Subject: "CN=WE1, O=Google Trust Services, C=US" -Issuer: "CN=GTS Root R4, O=Google Trust Services LLC, C=US" -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 7f:f3:19:77:97:2c:22:4a:76:15:5d:13:b6:d6:85:e3 - Signature Algorithm: ecdsa-with-SHA384 - Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R4 - Validity - Not Before: Dec 13 09:00:00 2023 GMT - Not After : Feb 20 14:00:00 2029 GMT - Subject: C=US, O=Google Trust Services, CN=WE1 - Subject Public Key Info: - Public Key Algorithm: id-ecPublicKey - Public-Key: (256 bit) - pub: - 04:6f:cd:3a:fe:67:57:47:4c:21:03:85:40:c2:47: - 5d:bb:58:47:0f:40:c1:5c:17:85:c6:19:37:e7:d5: - 7c:ed:86:4b:9b:81:d9:d7:1a:13:a5:0a:03:f8:98: - c4:c6:e8:9e:ff:10:59:8f:2c:26:98:f5:e6:26:25: - bb:0f:02:fa:56 - ASN1 OID: prime256v1 - NIST CURVE: P-256 - X509v3 extensions: - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Extended Key Usage: - TLS Web Server Authentication, TLS Web Client Authentication - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:0 - X509v3 Subject Key Identifier: - 90:77:92:35:67:C4:FF:A8:CC:A9:E6:7B:D9:80:79:7B:CC:93:F9:38 - X509v3 Authority Key Identifier: - keyid:80:4C:D6:EB:74:FF:49:36:A3:D5:D8:FC:B5:3E:C5:6A:F0:94:1D:8C - - Authority Information Access: - CA Issuers - URI:http://i.pki.goog/r4.crt - - X509v3 CRL Distribution Points: - - Full Name: - URI:http://c.pki.goog/r/r4.crl - - X509v3 Certificate Policies: - Policy: 2.23.140.1.2.1 - - Signature Algorithm: ecdsa-with-SHA384 - 30:65:02:31:00:e7:02:ab:51:d6:f7:43:95:ce:75:fe:d1:11: - 94:d5:cc:40:41:7a:26:be:d8:0c:f3:32:2d:3d:90:ae:15:0f: - 23:48:12:52:8f:3e:64:79:13:af:f5:a6:2c:02:6e:55:b1:02: - 30:26:89:cc:68:01:62:e7:89:ab:7e:17:e8:14:d6:44:7e:e3: - 4c:49:0e:bf:6c:80:62:34:b8:b2:a1:7e:3a:16:88:50:bc:a7: - 88:a0:9f:7d:73:1e:ec:52:41:4d:ee:e2:56 ------BEGIN CERTIFICATE----- -MIICnzCCAiWgAwIBAgIQf/MZd5csIkp2FV0TttaF4zAKBggqhkjOPQQDAzBHMQsw -CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU -MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMjMxMjEzMDkwMDAwWhcNMjkwMjIwMTQw -MDAwWjA7MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZp -Y2VzMQwwCgYDVQQDEwNXRTEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARvzTr+ -Z1dHTCEDhUDCR127WEcPQMFcF4XGGTfn1XzthkubgdnXGhOlCgP4mMTG6J7/EFmP -LCaY9eYmJbsPAvpWo4H+MIH7MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggr -BgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU -kHeSNWfE/6jMqeZ72YB5e8yT+TgwHwYDVR0jBBgwFoAUgEzW63T/STaj1dj8tT7F -avCUHYwwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzAChhhodHRwOi8vaS5wa2ku -Z29vZy9yNC5jcnQwKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL2MucGtpLmdvb2cv -ci9yNC5jcmwwEwYDVR0gBAwwCjAIBgZngQwBAgEwCgYIKoZIzj0EAwMDaAAwZQIx -AOcCq1HW90OVznX+0RGU1cxAQXomvtgM8zItPZCuFQ8jSBJSjz5keROv9aYsAm5V -sQIwJonMaAFi54mrfhfoFNZEfuNMSQ6/bIBiNLiyoX46FohQvKeIoJ99cx7sUkFN -7uJW ------END CERTIFICATE----- - -SHA-256 hash: 9c3f2fd11c57d7c649ad5a0932c0f0d29756f6a0a1c74c43e1e89a62d64cd320 -Subject: "CN=WE2, O=Google Trust Services, C=US" -Issuer: "CN=GTS Root R4, O=Google Trust Services LLC, C=US" -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 7f:f3:2d:6b:40:9d:15:d5:96:5b:05:87:3a:7c:72:e0 - Signature Algorithm: ecdsa-with-SHA384 - Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R4 - Validity - Not Before: Dec 13 09:00:00 2023 GMT - Not After : Feb 20 14:00:00 2029 GMT - Subject: C=US, O=Google Trust Services, CN=WE2 - Subject Public Key Info: - Public Key Algorithm: id-ecPublicKey - Public-Key: (256 bit) - pub: - 04:35:7e:1f:f2:14:ed:90:7d:e1:9e:2a:34:43:86: - c1:d5:96:e8:27:70:df:9e:04:cb:a9:ca:86:79:0b: - 08:4d:46:8a:c2:74:a4:bb:d9:bf:ee:fd:23:d7:38: - f3:4b:ef:54:17:e1:be:e7:ca:55:25:a8:0c:30:ac: - 2d:5d:4e:a1:51 - ASN1 OID: prime256v1 - NIST CURVE: P-256 - X509v3 extensions: - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Extended Key Usage: - TLS Web Server Authentication, TLS Web Client Authentication - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:0 - X509v3 Subject Key Identifier: - 75:BE:C4:77:AE:89:F6:44:37:7D:CF:B1:68:1F:1D:1A:EB:DC:34:59 - X509v3 Authority Key Identifier: - keyid:80:4C:D6:EB:74:FF:49:36:A3:D5:D8:FC:B5:3E:C5:6A:F0:94:1D:8C - - Authority Information Access: - CA Issuers - URI:http://i.pki.goog/r4.crt - - X509v3 CRL Distribution Points: - - Full Name: - URI:http://c.pki.goog/r/r4.crl - - X509v3 Certificate Policies: - Policy: 2.23.140.1.2.1 - - Signature Algorithm: ecdsa-with-SHA384 - 30:64:02:30:0b:bd:b8:36:55:c8:35:a3:d2:d9:7d:39:73:d3: - f7:f7:82:b8:09:d1:81:6f:e5:64:45:db:de:aa:c0:0e:45:12: - 8f:ac:93:e8:1f:60:ec:2e:7e:44:2c:22:94:91:ec:ac:02:30: - 2f:df:0c:90:76:4c:2d:69:61:d5:4f:fd:98:98:18:84:db:34: - ea:98:ec:9b:cd:88:62:ff:d2:65:e5:33:6a:9a:0c:ed:23:49: - 38:2f:51:bf:91:d0:12:a2:c9:38:38:da ------BEGIN CERTIFICATE----- -MIICnjCCAiWgAwIBAgIQf/Mta0CdFdWWWwWHOnxy4DAKBggqhkjOPQQDAzBHMQsw -CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU -MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMjMxMjEzMDkwMDAwWhcNMjkwMjIwMTQw -MDAwWjA7MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZp -Y2VzMQwwCgYDVQQDEwNXRTIwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQ1fh/y -FO2QfeGeKjRDhsHVlugncN+eBMupyoZ5CwhNRorCdKS72b/u/SPXOPNL71QX4b7n -ylUlqAwwrC1dTqFRo4H+MIH7MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggr -BgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU -db7Ed66J9kQ3fc+xaB8dGuvcNFkwHwYDVR0jBBgwFoAUgEzW63T/STaj1dj8tT7F -avCUHYwwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzAChhhodHRwOi8vaS5wa2ku -Z29vZy9yNC5jcnQwKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL2MucGtpLmdvb2cv -ci9yNC5jcmwwEwYDVR0gBAwwCjAIBgZngQwBAgEwCgYIKoZIzj0EAwMDZwAwZAIw -C724NlXINaPS2X05c9P394K4CdGBb+VkRdveqsAORRKPrJPoH2DsLn5ELCKUkeys -AjAv3wyQdkwtaWHVT/2YmBiE2zTqmOybzYhi/9Jl5TNqmgztI0k4L1G/kdASosk4 -ONo= ------END CERTIFICATE----- - -SHA-256 hash: 9f819a4c876e12dc84e6fe0e37c1a69b137094b453fa98449398f4b71f4d0092 -Subject: "CN=WE3, O=Google Trust Services, C=US" -Issuer: "CN=GTS Root R4, O=Google Trust Services LLC, C=US" -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 7f:f3:2d:6d:bd:5e:dd:54:ca:4e:4b:67:95:72:91:43 - Signature Algorithm: ecdsa-with-SHA384 - Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R4 - Validity - Not Before: Dec 13 09:00:00 2023 GMT - Not After : Feb 20 14:00:00 2029 GMT - Subject: C=US, O=Google Trust Services, CN=WE3 - Subject Public Key Info: - Public Key Algorithm: id-ecPublicKey - Public-Key: (256 bit) - pub: - 04:8c:72:71:5c:66:e5:04:54:96:79:1b:c1:c2:81: - 65:90:33:36:73:3c:c0:2f:b4:b9:54:06:2a:5a:34: - 27:95:91:35:09:aa:7a:bf:92:c9:8d:18:e8:56:92: - e2:4f:aa:6d:67:5a:6d:41:51:ac:0a:c3:75:c6:27: - b2:02:b7:c5:42 - ASN1 OID: prime256v1 - NIST CURVE: P-256 - X509v3 extensions: - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Extended Key Usage: - TLS Web Server Authentication, TLS Web Client Authentication - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:0 - X509v3 Subject Key Identifier: - 36:B6:2C:CE:A3:B4:D0:40:90:45:F3:8B:45:81:C1:C8:E3:19:D4:6D - X509v3 Authority Key Identifier: - keyid:80:4C:D6:EB:74:FF:49:36:A3:D5:D8:FC:B5:3E:C5:6A:F0:94:1D:8C - - Authority Information Access: - CA Issuers - URI:http://i.pki.goog/r4.crt - - X509v3 CRL Distribution Points: - - Full Name: - URI:http://c.pki.goog/r/r4.crl - - X509v3 Certificate Policies: - Policy: 2.23.140.1.2.1 - - Signature Algorithm: ecdsa-with-SHA384 - 30:65:02:31:00:82:6e:b7:32:b8:68:ec:a0:2b:98:c9:b4:5c: - cd:ad:70:5f:6c:c2:75:be:32:51:19:77:d3:d0:6e:18:ed:98: - 61:1a:c2:bc:f2:ce:a1:54:a0:42:35:99:cf:8f:3b:0c:db:02: - 30:43:ed:68:35:0d:4e:55:2d:ee:e5:0f:aa:a6:93:ac:6b:cf: - 1f:ef:3c:36:61:95:2e:33:37:27:3e:52:f7:a5:d8:30:40:e8: - b7:08:4f:0f:61:6a:26:fe:eb:0d:76:3f:ae ------BEGIN CERTIFICATE----- -MIICnzCCAiWgAwIBAgIQf/Mtbb1e3VTKTktnlXKRQzAKBggqhkjOPQQDAzBHMQsw -CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU -MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMjMxMjEzMDkwMDAwWhcNMjkwMjIwMTQw -MDAwWjA7MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZp -Y2VzMQwwCgYDVQQDEwNXRTMwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASMcnFc -ZuUEVJZ5G8HCgWWQMzZzPMAvtLlUBipaNCeVkTUJqnq/ksmNGOhWkuJPqm1nWm1B -UawKw3XGJ7ICt8VCo4H+MIH7MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggr -BgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU -NrYszqO00ECQRfOLRYHByOMZ1G0wHwYDVR0jBBgwFoAUgEzW63T/STaj1dj8tT7F -avCUHYwwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzAChhhodHRwOi8vaS5wa2ku -Z29vZy9yNC5jcnQwKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL2MucGtpLmdvb2cv -ci9yNC5jcmwwEwYDVR0gBAwwCjAIBgZngQwBAgEwCgYIKoZIzj0EAwMDaAAwZQIx -AIJutzK4aOygK5jJtFzNrXBfbMJ1vjJRGXfT0G4Y7ZhhGsK88s6hVKBCNZnPjzsM -2wIwQ+1oNQ1OVS3u5Q+qppOsa88f7zw2YZUuMzcnPlL3pdgwQOi3CE8PYWom/usN -dj+u ------END CERTIFICATE----- - -SHA-256 hash: d0c97e56c7b0ba812d944ad771f7799b5d4144a2327a4e416554f7ee2aa0aeae -Subject: "CN=WE4, O=Google Trust Services, C=US" -Issuer: "CN=GTS Root R4, O=Google Trust Services LLC, C=US" -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 7f:f3:2d:70:bb:d1:a7:30:9b:57:32:50:0a:c9:9a:ae - Signature Algorithm: ecdsa-with-SHA384 - Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R4 - Validity - Not Before: Dec 13 09:00:00 2023 GMT - Not After : Feb 20 14:00:00 2029 GMT - Subject: C=US, O=Google Trust Services, CN=WE4 - Subject Public Key Info: - Public Key Algorithm: id-ecPublicKey - Public-Key: (256 bit) - pub: - 04:c1:aa:09:fd:3c:dc:18:36:3e:db:eb:69:ad:7f: - 75:72:47:a1:c8:6c:2c:fd:28:bb:f5:60:51:77:c1: - ab:bc:ec:d2:21:f6:35:d2:5e:70:24:59:dd:fc:5b: - 13:39:3d:d1:5f:3b:d0:fb:cc:90:1d:6a:97:ff:a8: - f4:85:53:10:6c - ASN1 OID: prime256v1 - NIST CURVE: P-256 - X509v3 extensions: - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Extended Key Usage: - TLS Web Server Authentication, TLS Web Client Authentication - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:0 - X509v3 Subject Key Identifier: - 6D:E7:D4:65:B4:38:57:56:95:CD:E5:B4:77:5A:36:0A:DE:7D:52:A6 - X509v3 Authority Key Identifier: - keyid:80:4C:D6:EB:74:FF:49:36:A3:D5:D8:FC:B5:3E:C5:6A:F0:94:1D:8C - - Authority Information Access: - CA Issuers - URI:http://i.pki.goog/r4.crt - - X509v3 CRL Distribution Points: - - Full Name: - URI:http://c.pki.goog/r/r4.crl - - X509v3 Certificate Policies: - Policy: 2.23.140.1.2.1 - - Signature Algorithm: ecdsa-with-SHA384 - 30:64:02:30:37:cf:34:3e:33:c6:94:ca:07:f0:53:56:53:93: - c1:e5:bf:e5:69:a6:6a:47:01:b9:03:4b:08:b2:43:8c:ce:1c: - f3:6d:d8:b7:d1:85:24:09:e1:45:4d:f3:3d:15:42:94:02:30: - 46:76:60:39:6b:87:f8:09:da:d1:e9:71:40:91:b7:ee:51:7f: - d7:97:b7:78:e6:a1:aa:1d:98:3b:82:88:3a:2c:8e:7e:8c:34: - 35:71:dd:05:31:d3:ba:3f:59:0a:f2:5d ------BEGIN CERTIFICATE----- -MIICnjCCAiWgAwIBAgIQf/MtcLvRpzCbVzJQCsmarjAKBggqhkjOPQQDAzBHMQsw -CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU -MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMjMxMjEzMDkwMDAwWhcNMjkwMjIwMTQw -MDAwWjA7MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZp -Y2VzMQwwCgYDVQQDEwNXRTQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATBqgn9 -PNwYNj7b62mtf3VyR6HIbCz9KLv1YFF3wau87NIh9jXSXnAkWd38WxM5PdFfO9D7 -zJAdapf/qPSFUxBso4H+MIH7MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggr -BgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU -befUZbQ4V1aVzeW0d1o2Ct59UqYwHwYDVR0jBBgwFoAUgEzW63T/STaj1dj8tT7F -avCUHYwwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzAChhhodHRwOi8vaS5wa2ku -Z29vZy9yNC5jcnQwKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL2MucGtpLmdvb2cv -ci9yNC5jcmwwEwYDVR0gBAwwCjAIBgZngQwBAgEwCgYIKoZIzj0EAwMDZwAwZAIw -N880PjPGlMoH8FNWU5PB5b/laaZqRwG5A0sIskOMzhzzbdi30YUkCeFFTfM9FUKU -AjBGdmA5a4f4CdrR6XFAkbfuUX/Xl7d45qGqHZg7gog6LI5+jDQ1cd0FMdO6P1kK -8l0= ------END CERTIFICATE----- - -SHA-256 hash: 847409e63526f162753ac49f75218efaafa7d5c94ade9095ce72e7f6b6e3ac99 -Subject: "CN=WE5, O=Google Trust Services, C=US" -Issuer: "CN=GTS Root R3, O=Google Trust Services LLC, C=US" -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 7f:f4:e5:cb:ec:d9:81:f2:ad:fa:08:91:3c:ef:ab:14 - Signature Algorithm: ecdsa-with-SHA384 - Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R3 - Validity - Not Before: Dec 13 09:00:00 2023 GMT - Not After : Feb 20 14:00:00 2029 GMT - Subject: C=US, O=Google Trust Services, CN=WE5 - Subject Public Key Info: - Public Key Algorithm: id-ecPublicKey - Public-Key: (256 bit) - pub: - 04:88:0c:8d:e1:3a:e4:24:06:93:85:77:d6:1c:c0: - ec:1f:50:df:16:08:a4:90:a5:0e:3c:ca:ee:dc:e8: - 24:ed:0b:f3:83:88:3b:ae:75:eb:b7:e6:6f:1e:3b: - 4f:20:12:2b:b7:ec:b8:1e:ab:37:d7:fb:b5:ab:7e: - c7:5b:19:fe:a2 - ASN1 OID: prime256v1 - NIST CURVE: P-256 - X509v3 extensions: - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Extended Key Usage: - TLS Web Server Authentication, TLS Web Client Authentication - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:0 - X509v3 Subject Key Identifier: - D4:65:CB:38:C7:25:3C:28:6B:E9:7E:43:C3:A1:A1:B8:E4:4C:68:A0 - X509v3 Authority Key Identifier: - keyid:C1:F1:26:BA:A0:2D:AE:85:81:CF:D3:F1:2A:12:BD:B8:0A:67:FD:BC - - Authority Information Access: - CA Issuers - URI:http://i.pki.goog/r3.crt - - X509v3 CRL Distribution Points: - - Full Name: - URI:http://c.pki.goog/r/r3.crl - - X509v3 Certificate Policies: - Policy: 2.23.140.1.2.1 - - Signature Algorithm: ecdsa-with-SHA384 - 30:65:02:30:42:38:89:c6:9e:b1:7a:6c:18:53:ae:87:ea:5f: - 46:98:f2:7f:35:7a:84:96:aa:79:03:34:f3:d2:f8:e2:8d:1c: - e9:c2:fa:13:a3:4e:ae:7a:f1:41:b3:e8:a9:e6:ff:c6:02:31: - 00:b0:9d:15:48:1a:6f:a8:25:08:ea:cb:40:18:ea:0e:5d:5d: - a1:af:d1:79:0e:8f:5d:e4:70:30:35:8f:9c:24:8a:1f:16:00: - 9b:5a:12:21:c1:12:fd:51:34:c5:c5:e5:74 ------BEGIN CERTIFICATE----- -MIICnzCCAiWgAwIBAgIQf/Tly+zZgfKt+giRPO+rFDAKBggqhkjOPQQDAzBHMQsw -CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU -MBIGA1UEAxMLR1RTIFJvb3QgUjMwHhcNMjMxMjEzMDkwMDAwWhcNMjkwMjIwMTQw -MDAwWjA7MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZp -Y2VzMQwwCgYDVQQDEwNXRTUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASIDI3h -OuQkBpOFd9YcwOwfUN8WCKSQpQ48yu7c6CTtC/ODiDuudeu35m8eO08gEiu37Lge -qzfX+7WrfsdbGf6io4H+MIH7MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggr -BgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU -1GXLOMclPChr6X5Dw6GhuORMaKAwHwYDVR0jBBgwFoAUwfEmuqAtroWBz9PxKhK9 -uApn/bwwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzAChhhodHRwOi8vaS5wa2ku -Z29vZy9yMy5jcnQwKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL2MucGtpLmdvb2cv -ci9yMy5jcmwwEwYDVR0gBAwwCjAIBgZngQwBAgEwCgYIKoZIzj0EAwMDaAAwZQIw -QjiJxp6xemwYU66H6l9GmPJ/NXqElqp5AzTz0vjijRzpwvoTo06uevFBs+ip5v/G -AjEAsJ0VSBpvqCUI6stAGOoOXV2hr9F5Do9d5HAwNY+cJIofFgCbWhIhwRL9UTTF -xeV0 ------END CERTIFICATE----- - -SHA-256 hash: 812c212e9e45dc5005c7f47411183f5fb2ff1baee184d3354b2e93d78c280164 -Subject: "CN=AE1, O=Google Trust Services, C=US" -Issuer: "CN=GTS Root R4, O=Google Trust Services LLC, C=US" -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 7f:f4:e5:ce:36:a6:a1:fa:5e:e1:91:6c:08:d3:9b:7c - Signature Algorithm: ecdsa-with-SHA384 - Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R4 - Validity - Not Before: Dec 13 09:00:00 2023 GMT - Not After : Feb 20 14:00:00 2029 GMT - Subject: C=US, O=Google Trust Services, CN=AE1 - Subject Public Key Info: - Public Key Algorithm: id-ecPublicKey - Public-Key: (256 bit) - pub: - 04:7d:0a:5c:db:19:c0:d9:0c:d2:79:bf:e2:68:fc: - 45:e2:17:fa:be:4d:59:1b:89:1d:ca:c0:39:6f:8c: - ed:c0:47:a1:2f:88:2b:f5:cc:34:86:f5:9b:51:8d: - 0c:30:57:f1:d8:01:64:db:94:60:b9:e0:56:a3:8b: - e6:49:80:6a:aa - ASN1 OID: prime256v1 - NIST CURVE: P-256 - X509v3 extensions: - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Extended Key Usage: - TLS Web Server Authentication - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:0 - X509v3 Subject Key Identifier: - 48:89:60:F9:A3:7D:0C:EA:00:24:A2:DC:9F:07:CE:46:88:A8:32:3A - X509v3 Authority Key Identifier: - keyid:80:4C:D6:EB:74:FF:49:36:A3:D5:D8:FC:B5:3E:C5:6A:F0:94:1D:8C - - Authority Information Access: - CA Issuers - URI:http://i.pki.goog/r4.crt - - X509v3 CRL Distribution Points: - - Full Name: - URI:http://c.pki.goog/r/r4.crl - - X509v3 Certificate Policies: - Policy: 2.23.140.1.2.1 - - Signature Algorithm: ecdsa-with-SHA384 - 30:66:02:31:00:99:d3:28:77:7e:39:f3:e9:c1:1c:33:60:f0: - a3:43:6f:10:4a:db:b8:28:e5:43:e7:8d:16:e0:97:f4:30:78: - e0:20:5c:70:3c:84:5c:e8:09:83:29:f1:09:52:ce:3c:2b:02: - 31:00:f9:57:f6:d0:41:e5:28:16:27:3f:58:41:4b:3d:75:08: - 86:75:31:35:da:cd:5f:b0:10:bd:44:a7:8e:56:0d:1d:7f:3d: - bd:fe:43:32:db:be:2b:a3:91:ab:64:dc:c3:1e ------BEGIN CERTIFICATE----- -MIICljCCAhugAwIBAgIQf/Tlzjamofpe4ZFsCNObfDAKBggqhkjOPQQDAzBHMQsw -CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU -MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMjMxMjEzMDkwMDAwWhcNMjkwMjIwMTQw -MDAwWjA7MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZp -Y2VzMQwwCgYDVQQDEwNBRTEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR9Clzb -GcDZDNJ5v+Jo/EXiF/q+TVkbiR3KwDlvjO3AR6EviCv1zDSG9ZtRjQwwV/HYAWTb -lGC54Faji+ZJgGqqo4H0MIHxMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggr -BgEFBQcDATASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBRIiWD5o30M6gAk -otyfB85GiKgyOjAfBgNVHSMEGDAWgBSATNbrdP9JNqPV2Py1PsVq8JQdjDA0Bggr -BgEFBQcBAQQoMCYwJAYIKwYBBQUHMAKGGGh0dHA6Ly9pLnBraS5nb29nL3I0LmNy -dDArBgNVHR8EJDAiMCCgHqAchhpodHRwOi8vYy5wa2kuZ29vZy9yL3I0LmNybDAT -BgNVHSAEDDAKMAgGBmeBDAECATAKBggqhkjOPQQDAwNpADBmAjEAmdMod3458+nB -HDNg8KNDbxBK27go5UPnjRbgl/QweOAgXHA8hFzoCYMp8QlSzjwrAjEA+Vf20EHl -KBYnP1hBSz11CIZ1MTXazV+wEL1Ep45WDR1/Pb3+QzLbviujkatk3MMe ------END CERTIFICATE-----
diff --git a/net/data/ssl/chrome_root_store/root_store.md b/net/data/ssl/chrome_root_store/root_store.md index 45592b2..83a99a2 100644 --- a/net/data/ssl/chrome_root_store/root_store.md +++ b/net/data/ssl/chrome_root_store/root_store.md
@@ -1,7 +1,7 @@ <!-- mdformat off(generated) --> <!-- mdlint off(generated) --> # Chrome Root Store -Version: 20 +Version: 19 [TOC]
diff --git a/net/data/ssl/chrome_root_store/root_store.textproto b/net/data/ssl/chrome_root_store/root_store.textproto index ea1a26a7..3ff97fa 100644 --- a/net/data/ssl/chrome_root_store/root_store.textproto +++ b/net/data/ssl/chrome_root_store/root_store.textproto
@@ -8,7 +8,7 @@ # Version # should always be incremented up whenever this (or any pem file that # it references) is changed. -version_major: 20 +version_major: 19 # CN=Actalis Authentication Root CA, O=Actalis S.p.A./03358520967, L=Milan, C=IT # https://ssltest-a.actalis.it:8443 @@ -381,19 +381,16 @@ # CN=GTS Root R3, O=Google Trust Services LLC, C=US trust_anchors { sha256_hex: "34d8a73ee208d9bcdb0d956520934b4e40e69482596e8b6f73c8426b010a6f48" - trust_anchor_id: "11129.9.3" } # CN=GTS Root R1, O=Google Trust Services LLC, C=US trust_anchors { sha256_hex: "d947432abde7b7fa90fc2e6b59101b1280e0e1c7e4e40fa3c6887fff57a7f4cf" - trust_anchor_id: "11129.9.1" } # CN=GTS Root R4, O=Google Trust Services LLC, C=US trust_anchors { sha256_hex: "349dfa4058c5e263123b398ae795573c4e1313c83fe68f93556cd5e8031b3c7d" - trust_anchor_id: "11129.9.4" } # CN=GlobalSign, O=GlobalSign, OU=GlobalSign ECC Root CA - R4 @@ -404,7 +401,6 @@ # CN=GTS Root R2, O=Google Trust Services LLC, C=US trust_anchors { sha256_hex: "8d25cd97229dbf70356bda4eb3cc734031e24cf00fafcfd32dc76eb5841c7ea8" - trust_anchor_id: "11129.9.2" } # CN=Hongkong Post Root CA 3, O=Hongkong Post, L=Hong Kong, ST=Hong Kong, C=HK @@ -1475,102 +1471,3 @@ sha256_hex: "fe95a24e7f94978e58d99350ab7ab789774a987cd25187c128c191d207523bb1" eutl: true } - -# "CN=WR1, O=Google Trust Services, C=US" -additional_certs { - sha256_hex: "b10b6f00e609509e8700f6d34687a2bfce38ea05a8fdf1cdc40c3a2a0d0d0e45" - enforce_anchor_constraints: true - enforce_anchor_expiry: true - tls_trust_anchor: true - trust_anchor_id: "11129.9.5" -} - -# "CN=WR2, O=Google Trust Services, C=US" -additional_certs { - sha256_hex: "e6fe22bf45e4f0d3b85c59e02c0f495418e1eb8d3210f788d48cd5e1cb547cd4" - enforce_anchor_constraints: true - enforce_anchor_expiry: true - tls_trust_anchor: true - trust_anchor_id: "11129.9.6" -} - -# "CN=WR3, O=Google Trust Services, C=US" -additional_certs { - sha256_hex: "2fe357db13751ff9160e87354975b3407498f41c9bd16a48657866e6e5a9b4c7" - enforce_anchor_constraints: true - enforce_anchor_expiry: true - tls_trust_anchor: true - trust_anchor_id: "11129.9.7" -} - -# "CN=WR4, O=Google Trust Services, C=US" -additional_certs { - sha256_hex: "dc9416c2f855126d6de977677538f2f967ff4998e90dfa435a17219be077fc06" - enforce_anchor_constraints: true - enforce_anchor_expiry: true - tls_trust_anchor: true - trust_anchor_id: "11129.9.8" -} - -# "CN=WR5, O=Google Trust Services, C=US" -additional_certs { - sha256_hex: "ae0fc852280f1b87cedaf73cfb84cf106efec88e8294253af352ed4034460d7b" - enforce_anchor_constraints: true - enforce_anchor_expiry: true - tls_trust_anchor: true - trust_anchor_id: "11129.9.9" -} - -# "CN=WE1, O=Google Trust Services, C=US" -additional_certs { - sha256_hex: "1dfc1605fbad358d8bc844f76d15203fac9ca5c1a79fd4857ffaf2864fbebf96" - enforce_anchor_constraints: true - enforce_anchor_expiry: true - tls_trust_anchor: true - trust_anchor_id: "11129.9.10" -} - -# "CN=WE2, O=Google Trust Services, C=US" -additional_certs { - sha256_hex: "9c3f2fd11c57d7c649ad5a0932c0f0d29756f6a0a1c74c43e1e89a62d64cd320" - enforce_anchor_constraints: true - enforce_anchor_expiry: true - tls_trust_anchor: true - trust_anchor_id: "11129.9.11" -} - -# "CN=WE3, O=Google Trust Services, C=US" -additional_certs { - sha256_hex: "9f819a4c876e12dc84e6fe0e37c1a69b137094b453fa98449398f4b71f4d0092" - enforce_anchor_constraints: true - enforce_anchor_expiry: true - tls_trust_anchor: true - trust_anchor_id: "11129.9.12" -} - -# "CN=WE4, O=Google Trust Services, C=US" -additional_certs { - sha256_hex: "d0c97e56c7b0ba812d944ad771f7799b5d4144a2327a4e416554f7ee2aa0aeae" - enforce_anchor_constraints: true - enforce_anchor_expiry: true - tls_trust_anchor: true - trust_anchor_id: "11129.9.13" -} - -# "CN=WE5, O=Google Trust Services, C=US" -additional_certs { - sha256_hex: "847409e63526f162753ac49f75218efaafa7d5c94ade9095ce72e7f6b6e3ac99" - enforce_anchor_constraints: true - enforce_anchor_expiry: true - tls_trust_anchor: true - trust_anchor_id: "11129.9.14" -} - -# "CN=AE1, O=Google Trust Services, C=US" -additional_certs { - sha256_hex: "812c212e9e45dc5005c7f47411183f5fb2ff1baee184d3354b2e93d78c280164" - enforce_anchor_constraints: true - enforce_anchor_expiry: true - tls_trust_anchor: true - trust_anchor_id: "11129.9.15" -}
diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h index ef8982535..f575984 100644 --- a/net/http/http_network_transaction.h +++ b/net/http/http_network_transaction.h
@@ -18,7 +18,6 @@ #include "base/memory/scoped_refptr.h" #include "base/time/time.h" #include "build/buildflag.h" -#include "crypto/ec_private_key.h" #include "net/base/completion_once_callback.h" #include "net/base/completion_repeating_callback.h" #include "net/base/net_error_details.h"
diff --git a/net/http/http_stream_parser.h b/net/http/http_stream_parser.h index 16b0306c..3dc2367f 100644 --- a/net/http/http_stream_parser.h +++ b/net/http/http_stream_parser.h
@@ -16,7 +16,6 @@ #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" #include "base/time/time.h" -#include "crypto/ec_private_key.h" #include "net/base/completion_once_callback.h" #include "net/base/completion_repeating_callback.h" #include "net/base/net_errors.h"
diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc index b94e6283..563823c 100644 --- a/net/socket/ssl_client_socket_impl.cc +++ b/net/socket/ssl_client_socket_impl.cc
@@ -33,7 +33,6 @@ #include "base/task/sequenced_task_runner.h" #include "base/values.h" #include "build/build_config.h" -#include "crypto/ec_private_key.h" #include "crypto/openssl_util.h" #include "net/base/features.h" #include "net/base/ip_address.h"
diff --git a/net/spdy/spdy_http_stream_unittest.cc b/net/spdy/spdy_http_stream_unittest.cc index e88aeeb9..4fda997 100644 --- a/net/spdy/spdy_http_stream_unittest.cc +++ b/net/spdy/spdy_http_stream_unittest.cc
@@ -14,9 +14,6 @@ #include "base/memory/raw_ptr.h" #include "base/run_loop.h" #include "base/task/single_thread_task_runner.h" -#include "crypto/ec_private_key.h" -#include "crypto/ec_signature_creator.h" -#include "crypto/signature_creator.h" #include "net/base/chunked_upload_data_stream.h" #include "net/base/load_timing_info.h" #include "net/base/load_timing_info_test_util.h"
diff --git a/net/spdy/spdy_test_util_common.h b/net/spdy/spdy_test_util_common.h index 02b5d0c..76f2d9a 100644 --- a/net/spdy/spdy_test_util_common.h +++ b/net/spdy/spdy_test_util_common.h
@@ -16,7 +16,6 @@ #include "base/containers/span.h" #include "base/memory/raw_ptr.h" -#include "crypto/ec_private_key.h" #include "net/base/completion_once_callback.h" #include "net/base/host_mapping_rules.h" #include "net/base/proxy_server.h"
diff --git a/net/test/cert_builder.cc b/net/test/cert_builder.cc index 67d5e203..6d5b897e 100644 --- a/net/test/cert_builder.cc +++ b/net/test/cert_builder.cc
@@ -26,10 +26,8 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/time/time.h" -#include "crypto/ec_private_key.h" #include "crypto/hash.h" -#include "crypto/rsa_private_key.h" -#include "crypto/sha2.h" +#include "crypto/keypair.h" #include "net/cert/asn1_util.h" #include "net/cert/ct_objects_extractor.h" #include "net/cert/ct_serialization.h" @@ -1203,13 +1201,14 @@ } void CertBuilder::GenerateECKey() { - auto private_key = crypto::ECPrivateKey::Create(); - SetKey(bssl::UpRef(private_key->key())); + auto private_key = crypto::keypair::PrivateKey::GenerateEcP256(); + SetKey(bssl::UpRef(private_key.key())); } void CertBuilder::GenerateRSAKey() { - auto private_key = crypto::RSAPrivateKey::Create(2048); - SetKey(bssl::UpRef(private_key->key())); + // TODO(https://crbug.com/426228064): Can we just use a hardcoded key here? + auto private_key = crypto::keypair::PrivateKey::GenerateRsa2048(); + SetKey(bssl::UpRef(private_key.key())); } bool CertBuilder::UseKeyFromFile(const base::FilePath& key_file) {
diff --git a/testing/perf/cbb_ref_info/chrome/dev/Android.json b/testing/perf/cbb_ref_info/chrome/dev/Android.json index 1bc8403..77fa51e 100644 --- a/testing/perf/cbb_ref_info/chrome/dev/Android.json +++ b/testing/perf/cbb_ref_info/chrome/dev/Android.json
@@ -1 +1 @@ -{"browser":"Chrome","channel":"Dev","platform":"Android","version":"111.0.1111.1"} \ No newline at end of file +{"browser":"Chrome","channel":"Dev","platform":"Android","version":"139.0.7246.0"} \ No newline at end of file
diff --git a/testing/perf/cbb_ref_info/chrome/dev/Windows.json b/testing/perf/cbb_ref_info/chrome/dev/Windows.json index 9518f37..ab1f4cec 100644 --- a/testing/perf/cbb_ref_info/chrome/dev/Windows.json +++ b/testing/perf/cbb_ref_info/chrome/dev/Windows.json
@@ -1 +1 @@ -{"browser":"Chrome","channel":"Dev","platform":"Windows","version":"139.0.7232.3"} \ No newline at end of file +{"browser":"Chrome","channel":"Dev","platform":"Windows","version":"139.0.7246.0"} \ No newline at end of file
diff --git a/testing/perf/cbb_ref_info/chrome/dev/macOS.json b/testing/perf/cbb_ref_info/chrome/dev/macOS.json index db26d0b..44a01df 100644 --- a/testing/perf/cbb_ref_info/chrome/dev/macOS.json +++ b/testing/perf/cbb_ref_info/chrome/dev/macOS.json
@@ -1 +1 @@ -{"browser":"Chrome","channel":"Dev","platform":"Mac","version":"139.0.7232.3"} \ No newline at end of file +{"browser":"Chrome","channel":"Dev","platform":"Mac","version":"139.0.7246.2"} \ No newline at end of file
diff --git a/testing/perf/cbb_ref_info/chrome/stable/Android.json b/testing/perf/cbb_ref_info/chrome/stable/Android.json index c7e14fb5..62616e7e 100644 --- a/testing/perf/cbb_ref_info/chrome/stable/Android.json +++ b/testing/perf/cbb_ref_info/chrome/stable/Android.json
@@ -1 +1 @@ -{"browser":"Chrome","channel":"Stable","platform":"Android","version":"137.0.7151.89"} \ No newline at end of file +{"browser":"Chrome","channel":"Stable","platform":"Android","version":"138.0.7204.35"} \ No newline at end of file
diff --git a/testing/perf/cbb_ref_info/chrome/stable/Windows.json b/testing/perf/cbb_ref_info/chrome/stable/Windows.json index ed3f5e3..370e649a 100644 --- a/testing/perf/cbb_ref_info/chrome/stable/Windows.json +++ b/testing/perf/cbb_ref_info/chrome/stable/Windows.json
@@ -1 +1 @@ -{"browser":"Chrome","channel":"Stable","platform":"Windows","version":"137.0.7151.70"} \ No newline at end of file +{"browser":"Chrome","channel":"Stable","platform":"Windows","version":"138.0.7204.35"} \ No newline at end of file
diff --git a/testing/perf/cbb_ref_info/chrome/stable/macOS.json b/testing/perf/cbb_ref_info/chrome/stable/macOS.json index d9aabb7..1fb0b47 100644 --- a/testing/perf/cbb_ref_info/chrome/stable/macOS.json +++ b/testing/perf/cbb_ref_info/chrome/stable/macOS.json
@@ -1 +1 @@ -{"browser":"Chrome","channel":"Stable","platform":"Mac","version":"137.0.7151.70"} \ No newline at end of file +{"browser":"Chrome","channel":"Stable","platform":"Mac","version":"138.0.7204.35"} \ No newline at end of file
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 2d9408f4..d5b3b56 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -195,6 +195,21 @@ ] } ], + "AccessibilityManifestV3EspeakNGTts": [ + { + "platforms": [ + "chromeos" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "AccessibilityManifestV3EspeakNGTts" + ] + } + ] + } + ], "AccessibilityManifestV3GoogleTts": [ { "platforms": [ @@ -10379,6 +10394,21 @@ ] } ], + "ForceOffTextAutosizing": [ + { + "platforms": [ + "android" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "ForceOffTextAutosizing" + ] + } + ] + } + ], "ForestFeature": [ { "platforms": [
diff --git a/third_party/android_deps/autorolled/BUILD.gn b/third_party/android_deps/autorolled/BUILD.gn index b83c687..4893f1c 100644 --- a/third_party/android_deps/autorolled/BUILD.gn +++ b/third_party/android_deps/autorolled/BUILD.gn
@@ -653,7 +653,7 @@ # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. java_prebuilt("org_robolectric_robolectric_java") { - jar_path = "autorolled/cipd/libs/org_robolectric_robolectric/robolectric-4.15-beta-1.jar" + jar_path = "autorolled/cipd/libs/org_robolectric_robolectric/robolectric-4.15.jar" output_name = "org_robolectric_robolectric" requires_robolectric = true enable_bytecode_checks = false @@ -1045,7 +1045,7 @@ # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. java_prebuilt("org_robolectric_annotations_java") { - jar_path = "autorolled/cipd/libs/org_robolectric_annotations/annotations-4.15-beta-1.jar" + jar_path = "autorolled/cipd/libs/org_robolectric_annotations/annotations-4.15.jar" output_name = "org_robolectric_annotations" requires_robolectric = true enable_bytecode_checks = false @@ -1061,8 +1061,7 @@ # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. java_prebuilt("org_robolectric_junit_java") { - jar_path = - "autorolled/cipd/libs/org_robolectric_junit/junit-4.15-beta-1.jar" + jar_path = "autorolled/cipd/libs/org_robolectric_junit/junit-4.15.jar" output_name = "org_robolectric_junit" requires_robolectric = true enable_bytecode_checks = false @@ -1082,7 +1081,7 @@ # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. java_prebuilt("org_robolectric_nativeruntime_java") { - jar_path = "autorolled/cipd/libs/org_robolectric_nativeruntime/nativeruntime-4.15-beta-1.jar" + jar_path = "autorolled/cipd/libs/org_robolectric_nativeruntime/nativeruntime-4.15.jar" output_name = "org_robolectric_nativeruntime" requires_robolectric = true enable_bytecode_checks = false @@ -1120,7 +1119,8 @@ # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. java_prebuilt("org_robolectric_pluginapi_java") { - jar_path = "autorolled/cipd/libs/org_robolectric_pluginapi/pluginapi-4.15-beta-1.jar" + jar_path = + "autorolled/cipd/libs/org_robolectric_pluginapi/pluginapi-4.15.jar" output_name = "org_robolectric_pluginapi" requires_robolectric = true enable_bytecode_checks = false @@ -1140,7 +1140,7 @@ # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. java_prebuilt("org_robolectric_plugins_maven_dependency_resolver_java") { - jar_path = "autorolled/cipd/libs/org_robolectric_plugins_maven_dependency_resolver/plugins-maven-dependency-resolver-4.15-beta-1.jar" + jar_path = "autorolled/cipd/libs/org_robolectric_plugins_maven_dependency_resolver/plugins-maven-dependency-resolver-4.15.jar" output_name = "org_robolectric_plugins_maven_dependency_resolver" requires_robolectric = true enable_bytecode_checks = false @@ -1162,7 +1162,8 @@ # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. java_prebuilt("org_robolectric_resources_java") { - jar_path = "autorolled/cipd/libs/org_robolectric_resources/resources-4.15-beta-1.jar" + jar_path = + "autorolled/cipd/libs/org_robolectric_resources/resources-4.15.jar" output_name = "org_robolectric_resources" requires_robolectric = true enable_bytecode_checks = false @@ -1184,8 +1185,7 @@ # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. java_prebuilt("org_robolectric_sandbox_java") { - jar_path = - "autorolled/cipd/libs/org_robolectric_sandbox/sandbox-4.15-beta-1.jar" + jar_path = "autorolled/cipd/libs/org_robolectric_sandbox/sandbox-4.15.jar" output_name = "org_robolectric_sandbox" requires_robolectric = true enable_bytecode_checks = false @@ -1212,7 +1212,8 @@ # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. java_prebuilt("org_robolectric_shadowapi_java") { - jar_path = "autorolled/cipd/libs/org_robolectric_shadowapi/shadowapi-4.15-beta-1.jar" + jar_path = + "autorolled/cipd/libs/org_robolectric_shadowapi/shadowapi-4.15.jar" output_name = "org_robolectric_shadowapi" requires_robolectric = true enable_bytecode_checks = false @@ -1232,7 +1233,7 @@ # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. java_prebuilt("org_robolectric_shadows_framework_java") { - jar_path = "autorolled/cipd/libs/org_robolectric_shadows_framework/shadows-framework-4.15-beta-1.jar" + jar_path = "autorolled/cipd/libs/org_robolectric_shadows_framework/shadows-framework-4.15.jar" output_name = "org_robolectric_shadows_framework" requires_robolectric = true enable_bytecode_checks = false @@ -1262,8 +1263,7 @@ # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. java_prebuilt("org_robolectric_utils_java") { - jar_path = - "autorolled/cipd/libs/org_robolectric_utils/utils-4.15-beta-1.jar" + jar_path = "autorolled/cipd/libs/org_robolectric_utils/utils-4.15.jar" output_name = "org_robolectric_utils" requires_robolectric = true enable_bytecode_checks = false @@ -1284,7 +1284,7 @@ # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. java_prebuilt("org_robolectric_utils_reflector_java") { - jar_path = "autorolled/cipd/libs/org_robolectric_utils_reflector/utils-reflector-4.15-beta-1.jar" + jar_path = "autorolled/cipd/libs/org_robolectric_utils_reflector/utils-reflector-4.15.jar" output_name = "org_robolectric_utils_reflector" requires_robolectric = true enable_bytecode_checks = false
diff --git a/third_party/android_deps/autorolled/VERSION.txt b/third_party/android_deps/autorolled/VERSION.txt index 22731b6..13c3969 100644 --- a/third_party/android_deps/autorolled/VERSION.txt +++ b/third_party/android_deps/autorolled/VERSION.txt
@@ -1 +1 @@ -4bc8d74291af9db.0f8e8195c7ca8d7 \ No newline at end of file +d901501d174c0f2.58cc21899cd5827 \ No newline at end of file
diff --git a/third_party/android_deps/autorolled/bill_of_materials.json b/third_party/android_deps/autorolled/bill_of_materials.json index 39808c0d..d79b9572 100644 --- a/third_party/android_deps/autorolled/bill_of_materials.json +++ b/third_party/android_deps/autorolled/bill_of_materials.json
@@ -1767,17 +1767,17 @@ { "name": "annotations", "group": "org.robolectric", - "version": "4.15-beta-1" + "version": "4.15" }, { "name": "junit", "group": "org.robolectric", - "version": "4.15-beta-1" + "version": "4.15" }, { "name": "nativeruntime", "group": "org.robolectric", - "version": "4.15-beta-1" + "version": "4.15" }, { "name": "nativeruntime-dist-compat", @@ -1787,47 +1787,47 @@ { "name": "pluginapi", "group": "org.robolectric", - "version": "4.15-beta-1" + "version": "4.15" }, { "name": "plugins-maven-dependency-resolver", "group": "org.robolectric", - "version": "4.15-beta-1" + "version": "4.15" }, { "name": "resources", "group": "org.robolectric", - "version": "4.15-beta-1" + "version": "4.15" }, { "name": "robolectric", "group": "org.robolectric", - "version": "4.15-beta-1" + "version": "4.15" }, { "name": "sandbox", "group": "org.robolectric", - "version": "4.15-beta-1" + "version": "4.15" }, { "name": "shadowapi", "group": "org.robolectric", - "version": "4.15-beta-1" + "version": "4.15" }, { "name": "shadows-framework", "group": "org.robolectric", - "version": "4.15-beta-1" + "version": "4.15" }, { "name": "utils", "group": "org.robolectric", - "version": "4.15-beta-1" + "version": "4.15" }, { "name": "utils-reflector", "group": "org.robolectric", - "version": "4.15-beta-1" + "version": "4.15" }, { "name": "snakeyaml",
diff --git a/third_party/android_deps/autorolled/build.gradle b/third_party/android_deps/autorolled/build.gradle index 372189b..3490b690 100644 --- a/third_party/android_deps/autorolled/build.gradle +++ b/third_party/android_deps/autorolled/build.gradle
@@ -367,19 +367,19 @@ versionCache['org.ow2.asm:asm-tree'] = '9.8' versionCache['org.ow2.asm:asm-util'] = '7.0' versionCache['org.reactivestreams:reactive-streams'] = '1.0.3' -versionCache['org.robolectric:annotations'] = '4.15-beta-1' -versionCache['org.robolectric:junit'] = '4.15-beta-1' -versionCache['org.robolectric:nativeruntime'] = '4.15-beta-1' +versionCache['org.robolectric:annotations'] = '4.15' +versionCache['org.robolectric:junit'] = '4.15' +versionCache['org.robolectric:nativeruntime'] = '4.15' versionCache['org.robolectric:nativeruntime-dist-compat'] = '1.0.17' -versionCache['org.robolectric:pluginapi'] = '4.15-beta-1' -versionCache['org.robolectric:plugins-maven-dependency-resolver'] = '4.15-beta-1' -versionCache['org.robolectric:resources'] = '4.15-beta-1' -versionCache['org.robolectric:robolectric'] = '4.15-beta-1' -versionCache['org.robolectric:sandbox'] = '4.15-beta-1' -versionCache['org.robolectric:shadowapi'] = '4.15-beta-1' -versionCache['org.robolectric:shadows-framework'] = '4.15-beta-1' -versionCache['org.robolectric:utils'] = '4.15-beta-1' -versionCache['org.robolectric:utils-reflector'] = '4.15-beta-1' +versionCache['org.robolectric:pluginapi'] = '4.15' +versionCache['org.robolectric:plugins-maven-dependency-resolver'] = '4.15' +versionCache['org.robolectric:resources'] = '4.15' +versionCache['org.robolectric:robolectric'] = '4.15' +versionCache['org.robolectric:sandbox'] = '4.15' +versionCache['org.robolectric:shadowapi'] = '4.15' +versionCache['org.robolectric:shadows-framework'] = '4.15' +versionCache['org.robolectric:utils'] = '4.15' +versionCache['org.robolectric:utils-reflector'] = '4.15' versionCache['org.yaml:snakeyaml'] = '2.4' apply plugin: ChromiumPlugin
diff --git a/third_party/android_deps/autorolled/committed/libs/org_robolectric_annotations/README.chromium b/third_party/android_deps/autorolled/committed/libs/org_robolectric_annotations/README.chromium index 206cc814..8f05470 100644 --- a/third_party/android_deps/autorolled/committed/libs/org_robolectric_annotations/README.chromium +++ b/third_party/android_deps/autorolled/committed/libs/org_robolectric_annotations/README.chromium
@@ -1,7 +1,7 @@ Name: annotations Short Name: annotations -URL: http://robolectric.org -Version: 4.15-beta-1 +URL: https://robolectric.org +Version: 4.15 Update Mechanism: Autoroll License: Apache-2.0, MIT License File: LICENSE
diff --git a/third_party/android_deps/autorolled/committed/libs/org_robolectric_junit/README.chromium b/third_party/android_deps/autorolled/committed/libs/org_robolectric_junit/README.chromium index 73ebc95..86ea170 100644 --- a/third_party/android_deps/autorolled/committed/libs/org_robolectric_junit/README.chromium +++ b/third_party/android_deps/autorolled/committed/libs/org_robolectric_junit/README.chromium
@@ -1,7 +1,7 @@ Name: junit Short Name: junit -URL: http://robolectric.org -Version: 4.15-beta-1 +URL: https://robolectric.org +Version: 4.15 Update Mechanism: Autoroll License: Apache-2.0, MIT License File: LICENSE
diff --git a/third_party/android_deps/autorolled/committed/libs/org_robolectric_nativeruntime/README.chromium b/third_party/android_deps/autorolled/committed/libs/org_robolectric_nativeruntime/README.chromium index 31cae24..7b8526bc 100644 --- a/third_party/android_deps/autorolled/committed/libs/org_robolectric_nativeruntime/README.chromium +++ b/third_party/android_deps/autorolled/committed/libs/org_robolectric_nativeruntime/README.chromium
@@ -1,7 +1,7 @@ Name: nativeruntime Short Name: nativeruntime -URL: http://robolectric.org -Version: 4.15-beta-1 +URL: https://robolectric.org +Version: 4.15 Update Mechanism: Autoroll License: Apache-2.0, MIT License File: LICENSE
diff --git a/third_party/android_deps/autorolled/committed/libs/org_robolectric_pluginapi/README.chromium b/third_party/android_deps/autorolled/committed/libs/org_robolectric_pluginapi/README.chromium index 052635d4..af5b080 100644 --- a/third_party/android_deps/autorolled/committed/libs/org_robolectric_pluginapi/README.chromium +++ b/third_party/android_deps/autorolled/committed/libs/org_robolectric_pluginapi/README.chromium
@@ -1,7 +1,7 @@ Name: pluginapi Short Name: pluginapi -URL: http://robolectric.org -Version: 4.15-beta-1 +URL: https://robolectric.org +Version: 4.15 Update Mechanism: Autoroll License: Apache-2.0, MIT License File: LICENSE
diff --git a/third_party/android_deps/autorolled/committed/libs/org_robolectric_plugins_maven_dependency_resolver/README.chromium b/third_party/android_deps/autorolled/committed/libs/org_robolectric_plugins_maven_dependency_resolver/README.chromium index 51c5fc1..f3ce065 100644 --- a/third_party/android_deps/autorolled/committed/libs/org_robolectric_plugins_maven_dependency_resolver/README.chromium +++ b/third_party/android_deps/autorolled/committed/libs/org_robolectric_plugins_maven_dependency_resolver/README.chromium
@@ -1,7 +1,7 @@ Name: maven-dependency-resolver Short Name: plugins-maven-dependency-resolver -URL: http://robolectric.org -Version: 4.15-beta-1 +URL: https://robolectric.org +Version: 4.15 Update Mechanism: Autoroll License: Apache-2.0, MIT License File: LICENSE
diff --git a/third_party/android_deps/autorolled/committed/libs/org_robolectric_resources/README.chromium b/third_party/android_deps/autorolled/committed/libs/org_robolectric_resources/README.chromium index 8204e8a4..f140bb8 100644 --- a/third_party/android_deps/autorolled/committed/libs/org_robolectric_resources/README.chromium +++ b/third_party/android_deps/autorolled/committed/libs/org_robolectric_resources/README.chromium
@@ -1,7 +1,7 @@ Name: resources Short Name: resources -URL: http://robolectric.org -Version: 4.15-beta-1 +URL: https://robolectric.org +Version: 4.15 Update Mechanism: Autoroll License: Apache-2.0, MIT License File: LICENSE
diff --git a/third_party/android_deps/autorolled/committed/libs/org_robolectric_robolectric/README.chromium b/third_party/android_deps/autorolled/committed/libs/org_robolectric_robolectric/README.chromium index 87cf18d0..b6b4522e9 100644 --- a/third_party/android_deps/autorolled/committed/libs/org_robolectric_robolectric/README.chromium +++ b/third_party/android_deps/autorolled/committed/libs/org_robolectric_robolectric/README.chromium
@@ -1,7 +1,7 @@ Name: robolectric Short Name: robolectric -URL: http://robolectric.org -Version: 4.15-beta-1 +URL: https://robolectric.org +Version: 4.15 Update Mechanism: Autoroll License: Apache-2.0, MIT License File: LICENSE
diff --git a/third_party/android_deps/autorolled/committed/libs/org_robolectric_sandbox/README.chromium b/third_party/android_deps/autorolled/committed/libs/org_robolectric_sandbox/README.chromium index ccf0ac5a..0bd1bba 100644 --- a/third_party/android_deps/autorolled/committed/libs/org_robolectric_sandbox/README.chromium +++ b/third_party/android_deps/autorolled/committed/libs/org_robolectric_sandbox/README.chromium
@@ -1,7 +1,7 @@ Name: sandbox Short Name: sandbox -URL: http://robolectric.org -Version: 4.15-beta-1 +URL: https://robolectric.org +Version: 4.15 Update Mechanism: Autoroll License: Apache-2.0, MIT License File: LICENSE
diff --git a/third_party/android_deps/autorolled/committed/libs/org_robolectric_shadowapi/README.chromium b/third_party/android_deps/autorolled/committed/libs/org_robolectric_shadowapi/README.chromium index a93be96..29aa1d8d 100644 --- a/third_party/android_deps/autorolled/committed/libs/org_robolectric_shadowapi/README.chromium +++ b/third_party/android_deps/autorolled/committed/libs/org_robolectric_shadowapi/README.chromium
@@ -1,7 +1,7 @@ Name: shadowapi Short Name: shadowapi -URL: http://robolectric.org -Version: 4.15-beta-1 +URL: https://robolectric.org +Version: 4.15 Update Mechanism: Autoroll License: Apache-2.0, MIT License File: LICENSE
diff --git a/third_party/android_deps/autorolled/committed/libs/org_robolectric_shadows_framework/README.chromium b/third_party/android_deps/autorolled/committed/libs/org_robolectric_shadows_framework/README.chromium index 904628d..fc67729 100644 --- a/third_party/android_deps/autorolled/committed/libs/org_robolectric_shadows_framework/README.chromium +++ b/third_party/android_deps/autorolled/committed/libs/org_robolectric_shadows_framework/README.chromium
@@ -1,7 +1,7 @@ Name: framework Short Name: shadows-framework -URL: http://robolectric.org -Version: 4.15-beta-1 +URL: https://robolectric.org +Version: 4.15 Update Mechanism: Autoroll License: Apache-2.0, MIT License File: LICENSE
diff --git a/third_party/android_deps/autorolled/committed/libs/org_robolectric_utils/README.chromium b/third_party/android_deps/autorolled/committed/libs/org_robolectric_utils/README.chromium index 4144efcf..fc7a9c8 100644 --- a/third_party/android_deps/autorolled/committed/libs/org_robolectric_utils/README.chromium +++ b/third_party/android_deps/autorolled/committed/libs/org_robolectric_utils/README.chromium
@@ -1,7 +1,7 @@ Name: utils Short Name: utils -URL: http://robolectric.org -Version: 4.15-beta-1 +URL: https://robolectric.org +Version: 4.15 Update Mechanism: Autoroll License: Apache-2.0, MIT License File: LICENSE
diff --git a/third_party/android_deps/autorolled/committed/libs/org_robolectric_utils_reflector/README.chromium b/third_party/android_deps/autorolled/committed/libs/org_robolectric_utils_reflector/README.chromium index 7762fdc1..78179556 100644 --- a/third_party/android_deps/autorolled/committed/libs/org_robolectric_utils_reflector/README.chromium +++ b/third_party/android_deps/autorolled/committed/libs/org_robolectric_utils_reflector/README.chromium
@@ -1,7 +1,7 @@ Name: reflector Short Name: utils-reflector -URL: http://robolectric.org -Version: 4.15-beta-1 +URL: https://robolectric.org +Version: 4.15 Update Mechanism: Autoroll License: Apache-2.0, MIT License File: LICENSE
diff --git a/third_party/androidx/build.gradle b/third_party/androidx/build.gradle index c3196e99..b364da6 100644 --- a/third_party/androidx/build.gradle +++ b/third_party/androidx/build.gradle
@@ -307,7 +307,7 @@ google() maven { // This URL is generated by the fetch_all_androidx.py script. - url 'https://androidx.dev/snapshots/builds/13674351/artifacts/repository' + url 'https://androidx.dev/snapshots/builds/13676404/artifacts/repository' } mavenCentral() }
diff --git a/third_party/angle b/third_party/angle index cb43254..3b7528e 160000 --- a/third_party/angle +++ b/third_party/angle
@@ -1 +1 @@ -Subproject commit cb432540e120916a9f503be74d128be74ec2ae8e +Subproject commit 3b7528e1c70f8cbe5643d91e3647a502a348e29f
diff --git a/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom b/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom index a70aeca..eb13f89 100644 --- a/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom +++ b/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
@@ -10,7 +10,8 @@ // https://chromium.googlesource.com/chromium/src.git/+/HEAD/docs/use_counter_wiki.md // // Do not change assigned numbers of existing items: add new features -// to the end of the list. +// to the end of the list. It's OK to rename an existing feature without +// changing its numerical value. // // If you want to mark an item as no-longer-used, simply rename it, prefixing // "kOBSOLETE_" before the existing name.
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.h b/third_party/blink/renderer/core/css/resolver/style_resolver.h index 3afde96..5ce1ad5 100644 --- a/third_party/blink/renderer/core/css/resolver/style_resolver.h +++ b/third_party/blink/renderer/core/css/resolver/style_resolver.h
@@ -29,10 +29,10 @@ #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/css/color_scheme_flags.h" #include "third_party/blink/renderer/core/css/css_position_try_rule.h" +#include "third_party/blink/renderer/core/css/css_to_length_conversion_data.h" #include "third_party/blink/renderer/core/css/element_rule_collector.h" #include "third_party/blink/renderer/core/css/resolver/matched_properties_cache.h" #include "third_party/blink/renderer/core/css/resolver/style_builder.h" -#include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h" #include "third_party/blink/renderer/core/css/selector_checker.h" #include "third_party/blink/renderer/core/css/selector_filter.h" #include "third_party/blink/renderer/core/css/style_request.h" @@ -56,6 +56,7 @@ class PropertyHandle; class StyleCascade; class StyleRecalcContext; +class StyleResolverState; class StyleRuleUsageTracker; // This class selects a ComputedStyle for a given element in a document based on
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc index 1c12c0e3..fc845559b 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
@@ -6636,19 +6636,17 @@ return; } - // Maximum number of attempts to try to find a next object on the line or to - // navigate to a new line. Used to detect unlikely (but theoretically - // possible), loops. - constexpr int kMaxInlineCursorNextObjectCalls = 350000; - int runs = 0; - do { - runs++; InlineCursor line_cursor = cursor; // Moves to first LayoutObject that a11y cares about. line_cursor.MoveToNextInlineLeaf(); + // Maximum number of attempts to try to find a next object on the line. Used + // to + // detect unlikely (but theoretically possible), loops. + constexpr int kMaxInlineCursorNextObjectCalls = 250000; + int runs = 0; while (line_cursor) { runs++; @@ -6697,7 +6695,7 @@ } } cursor.MoveToNextLine(); - } while (cursor && runs < kMaxInlineCursorNextObjectCalls); + } while (cursor); } void AXObjectCacheImpl::ConnectToTrailingWhitespaceOnLine(
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.cc b/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.cc index 31b3ca8..2f67aa6 100644 --- a/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.cc +++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.cc
@@ -151,17 +151,14 @@ } } - for (const auto& param_name : param_value_map_.Keys()) { - auto* const param_handler = param_handler_map_.at(param_name); - AudioFloatArray* param_values = param_value_map_.at(param_name); + for (auto& entry : param_value_map_) { + auto* const param_handler = param_handler_map_.at(entry.key); + auto param_values = entry.value->as_span().first(frames_to_process); if (param_handler->HasSampleAccurateValues() && param_handler->IsAudioRate()) { - param_handler->CalculateSampleAccurateValues( - param_values->as_span().first(frames_to_process)); + param_handler->CalculateSampleAccurateValues(param_values); } else { - std::fill(param_values->Data(), - UNSAFE_TODO(param_values->Data() + frames_to_process), - param_handler->FinalValue()); + std::ranges::fill(param_values, param_handler->FinalValue()); } }
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc index c72713e4..3070f4fe 100644 --- a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc +++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc
@@ -1225,10 +1225,11 @@ // is not a black frame. #if BUILDFLAG(IS_WIN) { - // Check if the incoming frame is backed by unowned memory. This could - // happen when: 1. Zero-copy capture feature is turned on but device does - // not support MediaFoundation; 2. The video track gets disabled so black - // frames are sent. + // Check if the incoming frame is backed by owned or unowned memory type. + // This could happen when: 1. Zero-copy capture feature is turned on but + // device does not support MediaFoundation; 2. Zero-copy is enabled and + // video frame is backed up by an ArrayBuffer; 3. The video track gets + // disabled so black frames are sent. scoped_refptr<media::VideoFrame> frame; webrtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_buffer = frame_chunk.video_frame_buffer; @@ -1238,7 +1239,8 @@ if (frame_buffer->type() == webrtc::VideoFrameBuffer::Type::kNative) { frame = static_cast<WebRtcVideoFrameAdapterInterface*>(frame_buffer.get()) ->getMediaVideoFrame(); - if (frame->storage_type() == media::VideoFrame::STORAGE_UNOWNED_MEMORY) { + if (frame->storage_type() == media::VideoFrame::STORAGE_UNOWNED_MEMORY || + frame->storage_type() == media::VideoFrame::STORAGE_OWNED_MEMORY) { if (use_native_input_) { use_native_input_ = false; }
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_test.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_test.cc index ccae910..a8a1355 100644 --- a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_test.cc +++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_test.cc
@@ -128,7 +128,9 @@ public: FakeNativeBufferI420(int width, int height, bool allow_to_i420) : blink::WebRtcVideoFrameAdapter( - media::VideoFrame::CreateBlackFrame(gfx::Size(480, 360))), + media::VideoFrame::CreateBlackFrame(gfx::Size(480, 360)), + base::MakeRefCounted<WebRtcVideoFrameAdapter::SharedResources>( + nullptr)), width_(width), height_(height), allow_to_i420_(allow_to_i420), @@ -1318,8 +1320,12 @@ ASSERT_EQ(WEBRTC_VIDEO_CODEC_OK, rtc_encoder_->InitEncode(&codec, kVideoEncoderSettings)); +#if !BUILDFLAG(IS_WIN) auto frame = media::VideoFrame::CreateBlackFrame( gfx::Size(kInputFrameWidth, kInputFrameHeight)); +#else + auto frame = media::VideoFrame::CreateEOSFrame(); +#endif frame->set_timestamp(base::Milliseconds(1)); webrtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_adapter( new webrtc::RefCountedObject<WebRtcVideoFrameAdapter>(
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index fb76bb7..5691e27 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -3256,6 +3256,7 @@ name: "NavigationId", status: "experimental", origin_trial_feature_name: "SoftNavigationHeuristics", + implied_by: ["SoftNavigationHeuristics"], }, { name: "NavigatorContentUtils",
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 29c187c..2d38d7b 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -2287,6 +2287,9 @@ crbug.com/1074547 external/wpt/css/css-transitions/transitioncancel-002.html [ Timeout ] +# Was failing only on Mac15, but then found the confidence to fail more broadly. +crbug.com/419116790 external/wpt/webrtc/RTCDataChannel-close.html [ Failure Pass Crash Timeout ] + crbug.com/1113004 external/wpt/css/css-pseudo/active-selection-043.html [ Failure ] crbug.com/1100119 [ Mac ] external/wpt/css/css-pseudo/active-selection-051.html [ Failure ] crbug.com/1100119 [ Mac ] external/wpt/css/css-pseudo/active-selection-052.html [ Failure ] @@ -7141,7 +7144,6 @@ crbug.com/1349215 external/wpt/fullscreen/api/document-exit-fullscreen-nested-in-iframe.html [ Timeout ] # Sheriff 2022-11-21 -crbug.com/1380188 external/wpt/html/browsers/browsing-the-web/history-traversal/event-order/before-load-hash.html [ Failure Pass ] crbug.com/1385809 external/wpt/clipboard-apis/async-navigator-clipboard-basics.https.html [ Failure Pass Timeout ] # Sheriff 2022-11-21 - EMEA @@ -8090,7 +8092,6 @@ crbug.com/356930166 [ Mac15 ] external/wpt/webrtc/protocol/rtp-demuxing.html [ Skip Timeout ] crbug.com/356930166 [ Mac15 ] external/wpt/webrtc/protocol/split.https.html [ Timeout ] crbug.com/356930166 [ Mac15 ] external/wpt/webrtc/RTCDataChannel-bufferedAmount.html [ Skip Timeout ] -crbug.com/356930166 [ Mac15 ] external/wpt/webrtc/RTCDataChannel-close.html [ Skip Timeout ] crbug.com/356930166 [ Mac15 ] external/wpt/webrtc/RTCDataChannel-iceRestart.html [ Skip Timeout ] crbug.com/356930166 [ Mac14 ] external/wpt/webrtc/RTCDataChannel-send-blob-order.html [ Timeout ] crbug.com/356930166 [ Mac15 ] external/wpt/webrtc/RTCDataChannel-send-blob-order.html [ Timeout ] @@ -8153,7 +8154,6 @@ crbug.com/356930166 [ Mac15-arm64 ] external/wpt/webrtc/protocol/rtp-demuxing.html [ Skip Timeout ] crbug.com/356930166 [ Mac15-arm64 ] external/wpt/webrtc/protocol/split.https.html [ Timeout ] crbug.com/356930166 [ Mac15-arm64 ] external/wpt/webrtc/RTCDataChannel-bufferedAmount.html [ Skip Timeout ] -crbug.com/356930166 [ Mac15-arm64 ] external/wpt/webrtc/RTCDataChannel-close.html [ Skip Timeout ] crbug.com/356930166 [ Mac15-arm64 ] external/wpt/webrtc/RTCDataChannel-iceRestart.html [ Skip Timeout ] crbug.com/356930166 [ Mac15-arm64 ] external/wpt/webrtc/RTCDataChannel-send-blob-order.html [ Timeout ] crbug.com/356930166 [ Mac15-arm64 ] external/wpt/webrtc/RTCDataChannel-send-close.html [ Skip Timeout ]
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/history-traversal/event-order/before-load-hash-twice.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/history-traversal/event-order/before-load-hash-twice.html index 7c8df11..7c3bc48 100644 --- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/history-traversal/event-order/before-load-hash-twice.html +++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/history-traversal/event-order/before-load-hash-twice.html
@@ -4,26 +4,35 @@ <script> // Set these up super-early before we hit the network for the test harness, just in case. -window.eventOrder = []; -window.onhashchange = () => window.eventOrder.push("hashchange"); -window.onpopstate = () => window.eventOrder.push("popstate"); -window.onload = () => window.eventOrder.push("load"); +let hashchangesLeft = 2; +let popstatesLeft = 2; +let hashResolve; +let hashPromise = new Promise(r => hashResolve = r); + +window.onhashchange = () => { + hashchangesLeft--; + if (hashchangesLeft == 0) { + hashResolve(); + } +} +window.onpopstate = () => popstatesLeft--; </script> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script> -async_test(t => { - assert_array_equals(window.eventOrder, []); - - window.addEventListener("load", t.step_func_done(() => { - assert_array_equals(window.eventOrder, ["popstate", "popstate", "hashchange", "hashchange", "load"]); - })); +promise_test(t => { + assert_equals(popstatesLeft, 2); location.hash = "#1"; - assert_array_equals(window.eventOrder, ["popstate"]); + assert_equals(popstatesLeft, 1); location.hash = "#2"; - assert_array_equals(window.eventOrder, ["popstate", "popstate"]); + assert_equals(popstatesLeft, 0); + + // hashchange and load are specced to fire on different task sources, and + // their ordering is therefore not guaranteed. + assert_equals(hashchangesLeft, 2); + return Promise.all([hashPromise, new Promise(r => window.onload = r)]); }, "when changing hash twice, before load"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/history-traversal/event-order/before-load-hash.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/history-traversal/event-order/before-load-hash.html index 97c4636..ccbb37e 100644 --- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/history-traversal/event-order/before-load-hash.html +++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/history-traversal/event-order/before-load-hash.html
@@ -4,24 +4,33 @@ <script> // Set these up super-early before we hit the network for the test harness, just in case. -window.eventOrder = []; -window.onhashchange = () => window.eventOrder.push("hashchange"); -window.onpopstate = () => window.eventOrder.push("popstate"); -window.onload = () => window.eventOrder.push("load"); +let hashchangesLeft = 1; +let popstatesLeft = 1; +let hashResolve; +let hashPromise = new Promise(r => hashResolve = r); + +window.onhashchange = () => { + hashchangesLeft--; + if (hashchangesLeft == 0) { + hashResolve(); + } +} +window.onpopstate = () => popstatesLeft--; </script> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script> -async_test(t => { - assert_array_equals(window.eventOrder, []); - - window.addEventListener("load", t.step_func_done(() => { - assert_array_equals(window.eventOrder, ["popstate", "hashchange", "load"]); - })); +promise_test(t => { + assert_equals(popstatesLeft, 1); location.hash = "#1"; - assert_array_equals(window.eventOrder, ["popstate"]); + assert_equals(popstatesLeft, 0); + + // hashchange and load are specced to fire on different task sources, and + // their ordering is therefore not guaranteed. + assert_equals(hashchangesLeft, 1); + return Promise.all([hashPromise, new Promise(r => window.onload = r)]); }, "when changing hash, before load"); </script>
diff --git a/third_party/blink/web_tests/platform/mac-mac12/external/wpt/html/browsers/browsing-the-web/history-traversal/event-order/before-load-hash-twice-expected.txt b/third_party/blink/web_tests/platform/mac-mac12/external/wpt/html/browsers/browsing-the-web/history-traversal/event-order/before-load-hash-twice-expected.txt deleted file mode 100644 index ab0f443..0000000 --- a/third_party/blink/web_tests/platform/mac-mac12/external/wpt/html/browsers/browsing-the-web/history-traversal/event-order/before-load-hash-twice-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -This is a testharness.js-based test. -[FAIL] when changing hash twice, before load - assert_array_equals: lengths differ, expected array ["popstate", "popstate", "hashchange", "hashchange", "load"] length 5, got ["popstate", "popstate", "load"] length 3 -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/compositing-op-non-opaque-element-ref.html b/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/compositing-op-non-opaque-element-ref.html new file mode 100644 index 0000000..ab367984 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/compositing-op-non-opaque-element-ref.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<title>Canvas.drawElement: transparent background rect composited (ref)</title> +<link rel="help" href="https://github.com/WICG/html-in-canvas"> +<link rel="author" href="mailto:schenney@chromium.org"> +<style> +#canvas { + background: grey; +} +</style> + +<canvas id=canvas width="200" height="200" layoutsubtree> +</canvas> + +<script> +function runTest() { + var context = canvas.getContext("2d"); + context.fillStyle = "blue"; + context.fillRect(10, 10, 180, 180); + context.globalCompositeOperation = "destination-out"; + context.fillStyle = "green"; + context.fillRect(20, 30, 20, 20); + context.fillRect(20, 110, 20, 20); + context.fillRect(100, 30, 20, 20); + context.fillRect(100, 110, 20, 20); +} + +onload = () => runTest(); + +</script>
diff --git a/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/compositing-op-non-opaque-element.html b/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/compositing-op-non-opaque-element.html new file mode 100644 index 0000000..b870dcc --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/compositing-op-non-opaque-element.html
@@ -0,0 +1,45 @@ +<!DOCTYPE html> +<html> +<title>Canvas.drawElement: non opaque element with compositing op</title> +<link rel="help" href="https://github.com/WICG/html-in-canvas"> +<link rel="author" href="mailto:schenney@chromium.org"> +<link rel="match" href="compositing-op-non-opaque-element-ref.html"> +<style> +#child { + width: 100px; + height: 100px; + background: transparent; +} +#canvas { + background: grey; +} +.grandchild { + background: green; + position: absolute; + width: 20px; + height: 20px; +} +</style> + +<canvas id=canvas width="200" height="200" layoutsubtree> + <div id=child> + <div class="grandchild" style="left: 0px; top: 0px"></div> + <div class="grandchild" style="left: 80px; top: 0px"></div> + <div class="grandchild" style="left: 0px; top: 80px"></div> + <div class="grandchild" style="left: 80px; top: 80px"></div> + </div> +</canvas> + +<script> +function runTest() { + var context = canvas.getContext("2d"); + context.fillStyle = "blue"; + context.fillRect(10, 10, 180, 180); + context.globalCompositeOperation = "destination-out"; + context.drawElement(child, 20, 30); +} + +onload = () => runTest(); + +</script> +</html>
diff --git a/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/non-opaque-element-ref.html b/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/non-opaque-element-ref.html new file mode 100644 index 0000000..546ce4d --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/non-opaque-element-ref.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<title>Canvas.drawElement: transparent background rect (ref)</title> +<link rel="help" href="https://github.com/WICG/html-in-canvas"> +<link rel="author" href="mailto:schenney@chromium.org"> +<style> +#child { + width: 100px; + height: 100px; + background: transparent; + + position: relative; + left: 20px; + top: 30px; +} +.grandchild { + position: absolute; + background: green; + width: 20px; + height: 20px; +} +#canvas { + width: 200px; + height: 200px; + background: grey; +} +</style> + +<div id=canvas> + <div id=child> + <div class="grandchild" style="left: 0px; top:0px"></div> + <div class="grandchild" style="left: 80px; top:0px"></div> + <div class="grandchild" style="left: 0px; top:80px"></div> + <div class="grandchild" style="left: 80px; top:80px"></div> + </div> +</div>
diff --git a/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/non-opaque-element.html b/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/non-opaque-element.html new file mode 100644 index 0000000..8858efda --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/non-opaque-element.html
@@ -0,0 +1,41 @@ +<!DOCTYPE html> +<html> +<title>Canvas.drawElement: div with transparent background</title> +<link rel="help" href="https://github.com/WICG/html-in-canvas"> +<link rel="author" href="mailto:schenney@chromium.org"> +<link rel="match" href="non-opaque-element-ref.html"> +<style> +#child { + width: 100px; + height: 100px; + background: transparent; +} +#canvas { + background: grey; +} +.grandchild { + background: green; + position: absolute; + width: 20px; + height: 20px; +} +</style> + +<canvas id=canvas width="200" height="200" layoutsubtree> + <div id=child> + <div class="grandchild" style="left: 0px; top: 0px"></div> + <div class="grandchild" style="left: 80px; top: 0px"></div> + <div class="grandchild" style="left: 0px; top: 80px"></div> + <div class="grandchild" style="left: 80px; top: 80px"></div> + </div> +</canvas> + +<script> +function runTest() { + canvas.getContext("2d").drawElement(child, 20, 30); +} + +onload = () => runTest(); + +</script> +</html>
diff --git a/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/shadow-basic.html b/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/shadow-basic.html index 368088d..f543735f 100644 --- a/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/shadow-basic.html +++ b/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/shadow-basic.html
@@ -4,7 +4,7 @@ <link rel="help" href="https://github.com/WICG/html-in-canvas"> <link rel="author" href="mailto:schenney@chromium.org"> <link rel="match" href="shadow-basic-ref.html"> -<meta name=fuzzy content="2;1989"> +<meta name=fuzzy content="0-2;0-1990"> <style> #child { width: 100px;
diff --git a/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/shadow-non-opaque-element-ref.html b/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/shadow-non-opaque-element-ref.html new file mode 100644 index 0000000..a28bd4e --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/shadow-non-opaque-element-ref.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<title>Canvas.drawElement: transparent background rect composited (ref)</title> +<link rel="help" href="https://github.com/WICG/html-in-canvas"> +<link rel="author" href="mailto:schenney@chromium.org"> +<style> +#canvas { + background: grey; +} +</style> + +<canvas id=canvas width="200" height="200" layoutsubtree> +</canvas> + +<script> +function runTest() { + var context = canvas.getContext("2d"); + context.shadowColor = "black"; + context.shadowBlur = 5; + context.shadowOffsetX = 20; + context.shadowOffsetY = 10; + context.fillStyle = "green"; + context.fillRect(20, 30, 20, 20); + context.fillRect(20, 110, 20, 20); + context.fillRect(100, 30, 20, 20); + context.fillRect(100, 110, 20, 20); +} + +onload = () => runTest(); + +</script>
diff --git a/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/shadow-non-opaque-element.html b/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/shadow-non-opaque-element.html new file mode 100644 index 0000000..59d18fb6 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/shadow-non-opaque-element.html
@@ -0,0 +1,47 @@ +<!DOCTYPE html> +<html> +<title>Canvas.drawElement: non opaque element with compositing op</title> +<link rel="help" href="https://github.com/WICG/html-in-canvas"> +<link rel="author" href="mailto:schenney@chromium.org"> +<link rel="match" href="shadow-non-opaque-element-ref.html"> +<meta name=fuzzy content="0-2;0-2185"> +<style> +#child { + width: 100px; + height: 100px; + background: transparent; +} +#canvas { + background: grey; +} +.grandchild { + background: green; + position: absolute; + width: 20px; + height: 20px; +} +</style> + +<canvas id=canvas width="200" height="200" layoutsubtree> + <div id=child> + <div class="grandchild" style="left: 0px; top: 0px"></div> + <div class="grandchild" style="left: 80px; top: 0px"></div> + <div class="grandchild" style="left: 0px; top: 80px"></div> + <div class="grandchild" style="left: 80px; top: 80px"></div> + </div> +</canvas> + +<script> +function runTest() { + var context = canvas.getContext("2d"); + context.shadowColor = "black"; + context.shadowBlur = 5; + context.shadowOffsetX = 20; + context.shadowOffsetY = 10; + context.drawElement(child, 20, 30); +} + +onload = () => runTest(); + +</script> +</html>
diff --git a/third_party/dawn b/third_party/dawn index 5602ae0..56724d2 160000 --- a/third_party/dawn +++ b/third_party/dawn
@@ -1 +1 @@ -Subproject commit 5602ae03628ac1ae4ba8d265ac1979abea42d6ba +Subproject commit 56724d23899220ea9a775b4ab4458e6ebc53ad52
diff --git a/third_party/llvm-libc/src b/third_party/llvm-libc/src index e09972e..79a5aa1 160000 --- a/third_party/llvm-libc/src +++ b/third_party/llvm-libc/src
@@ -1 +1 @@ -Subproject commit e09972e0948f01cace57c08ba82b61fc171c739c +Subproject commit 79a5aa1b7fcbdf3397bc2a08cbd6ef5c302dfb5a
diff --git a/third_party/perfetto b/third_party/perfetto index 21d660f..cca1748 160000 --- a/third_party/perfetto +++ b/third_party/perfetto
@@ -1 +1 @@ -Subproject commit 21d660f5550822d7bcf79c43595ffbf258fe681a +Subproject commit cca1748cb16b9dc0cac21515813c3855a983917d
diff --git a/third_party/spirv-tools/src b/third_party/spirv-tools/src index 85607567..108b19e 160000 --- a/third_party/spirv-tools/src +++ b/third_party/spirv-tools/src
@@ -1 +1 @@ -Subproject commit 85607567adde930f1598024116caa1ff9831848c +Subproject commit 108b19e5c6979f496deffad4acbe354237afa7d3
diff --git a/third_party/vulkan-deps b/third_party/vulkan-deps index 565c281..49cfa53 160000 --- a/third_party/vulkan-deps +++ b/third_party/vulkan-deps
@@ -1 +1 @@ -Subproject commit 565c281d73214e4712bd78be4cb7ccc2833ea471 +Subproject commit 49cfa5309d365d4ea40bd92b399595c30d8dc96e
diff --git a/third_party/vulkan-loader/src b/third_party/vulkan-loader/src index dc6786e..c8a2c8c9 160000 --- a/third_party/vulkan-loader/src +++ b/third_party/vulkan-loader/src
@@ -1 +1 @@ -Subproject commit dc6786e527cf8cefd244318f546b3b2ec26e84f4 +Subproject commit c8a2c8c9164a58ce71c1c77104e28e8de724539e
diff --git a/third_party/vulkan-tools/src b/third_party/vulkan-tools/src index d6719230..e3fc643 160000 --- a/third_party/vulkan-tools/src +++ b/third_party/vulkan-tools/src
@@ -1 +1 @@ -Subproject commit d671923090e4dc74c0ebdb10c6e09fa0826e1fe9 +Subproject commit e3fc64396755191b3c51e5c57d0454872e7fa487
diff --git a/third_party/vulkan-utility-libraries/src b/third_party/vulkan-utility-libraries/src index 54c9baf..0f0babb 160000 --- a/third_party/vulkan-utility-libraries/src +++ b/third_party/vulkan-utility-libraries/src
@@ -1 +1 @@ -Subproject commit 54c9baf20802a13279e23fa4cb0528dd5cf16064 +Subproject commit 0f0babb553a60da5971d9f4d40cf720ce01602f1
diff --git a/tools/metrics/histograms/metadata/ios/enums.xml b/tools/metrics/histograms/metadata/ios/enums.xml index ff424b1..9c0e1dd1 100644 --- a/tools/metrics/histograms/metadata/ios/enums.xml +++ b/tools/metrics/histograms/metadata/ios/enums.xml
@@ -264,6 +264,13 @@ <int value="2" label="Open tabs"/> </enum> +<enum name="IOSBWGEntryPoint"> + <int value="0" label="Promo"/> + <int value="1" label="Overflow Menu"/> + <int value="2" label="AI Hub"/> + <int value="3" label="Omnibox Chip"/> +</enum> + <enum name="iOSCredentialIdentityStoreErrorForReporting"> <int value="0" label="Unknown Error"/> <int value="1" label="Internal Error"/>
diff --git a/tools/metrics/histograms/metadata/ios/histograms.xml b/tools/metrics/histograms/metadata/ios/histograms.xml index c4f4a46..fb3a36e 100644 --- a/tools/metrics/histograms/metadata/ios/histograms.xml +++ b/tools/metrics/histograms/metadata/ios/histograms.xml
@@ -385,6 +385,26 @@ </summary> </histogram> +<histogram name="IOS.BWG.EntryPoint" enum="IOSBWGEntryPoint" + expires_after="2026-02-01"> + <owner>sebsg@chromium.org</owner> + <owner>bling-alchemy@google.com</owner> + <summary> + Records the entry point source from which BWG was triggered. Recorded when + BWG is triggered. + </summary> +</histogram> + +<histogram name="IOS.BWG.FRE.EntryPoint" enum="IOSBWGEntryPoint" + expires_after="2026-02-01"> + <owner>sebsg@chromium.org</owner> + <owner>bling-alchemy@google.com</owner> + <summary> + Records the entry point source from which BWG First Run Experience (FRE) was + triggered. Recorded when the BWG FRE is triggered. + </summary> +</histogram> + <histogram name="IOS.CaptivePortal.SecureConnectionFailed" enum="CaptivePortalStatus" expires_after="2023-09-07"> <owner>michaeldo@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/windows/enums.xml b/tools/metrics/histograms/metadata/windows/enums.xml index bd2ba05..76259b10 100644 --- a/tools/metrics/histograms/metadata/windows/enums.xml +++ b/tools/metrics/histograms/metadata/windows/enums.xml
@@ -128,6 +128,20 @@ <int value="2" label="Unknown"/> </enum> +<!-- LINT.IfChange(SystemInstallerLaunchStatus) --> + +<enum name="SystemInstallerLaunchStatus"> + <summary> + Status of launching the platform experience helper installer for system + installs. + </summary> + <int value="0" label="Success"/> + <int value="1" label="App command not found"/> + <int value="2" label="App command execution failed"/> +</enum> + +<!-- LINT.ThenChange(//chrome/browser/platform_experience/installer/installer_win.cc:SystemInstallerLaunchStatus) --> + <enum name="TaskbarPinResult"> <!-- This is used when recording if Chrome should offer to pin to the taskbar, @@ -154,6 +168,21 @@ <int value="7" label="Pin failed">Pin failed, e.g., user didn't confirm</int> </enum> +<!-- LINT.IfChange(UserInstallerLaunchStatus) --> + +<enum name="UserInstallerLaunchStatus"> + <summary> + Status of launching the platform experience helper installer for user + installs. + </summary> + <int value="0" label="Success"/> + <int value="1" label="File not found"/> + <int value="2" label="Access denied"/> + <int value="3" label="Other failure"/> +</enum> + +<!-- LINT.ThenChange(//chrome/browser/platform_experience/installer/installer_win.cc:UserInstallerLaunchStatus) --> + <enum name="WindowsPatchLevel"> <!-- These can be generated by visiting https://bit.ly/2JQr6rB -->
diff --git a/tools/metrics/histograms/metadata/windows/histograms.xml b/tools/metrics/histograms/metadata/windows/histograms.xml index d00b278c..5b363c9 100644 --- a/tools/metrics/histograms/metadata/windows/histograms.xml +++ b/tools/metrics/histograms/metadata/windows/histograms.xml
@@ -320,6 +320,26 @@ </summary> </histogram> +<histogram name="Windows.PlatformExperienceHelper.InstallerLaunchStatus.System" + enum="SystemInstallerLaunchStatus" expires_after="2025-12-01"> + <owner>alsan@chromium.org</owner> + <owner>chrome-desktop-ui-waterloo@google.com</owner> + <summary> + Records the outcome of attempting to launch the platform experience helper + installer via Google Update for system installs. + </summary> +</histogram> + +<histogram name="Windows.PlatformExperienceHelper.InstallerLaunchStatus.User" + enum="UserInstallerLaunchStatus" expires_after="2025-12-01"> + <owner>alsan@chromium.org</owner> + <owner>chrome-desktop-ui-waterloo@google.com</owner> + <summary> + Records the outcome of attempting to launch the platform experience helper + installer executable directly for user installs. + </summary> +</histogram> + <histogram name="Windows.ProcessorFamily" enum="ProcessorFamily" expires_after="2025-12-14"> <owner>rkc@chromium.org</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index f80c902..faac5d59 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,8 +5,8 @@ "full_remote_path": "perfetto-luci-artifacts/3940ed807f48affbec08603c79e957d10e4a6ef4/linux-arm64/trace_processor_shell" }, "win": { - "hash": "ca33458e191a3a1a54300c3f2e6df7463cbd02f1", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/b6d5ffb271cc26946597529583efb3a4a2c967dc/trace_processor_shell.exe" + "hash": "8ed2c403121faa058244678ef38e20a265851091", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/cca1748cb16b9dc0cac21515813c3855a983917d/trace_processor_shell.exe" }, "linux_arm": { "hash": "be8386e1db86d436e39624fdbcff5b6586bedfdd",
diff --git a/ui/android/java/res/values/semantic_colors_non_adaptive.xml b/ui/android/java/res/values/semantic_colors_non_adaptive.xml index 882afdf..9d57875 100644 --- a/ui/android/java/res/values/semantic_colors_non_adaptive.xml +++ b/ui/android/java/res/values/semantic_colors_non_adaptive.xml
@@ -136,7 +136,7 @@ <color name="tab_strip_favicon_bg_incognito">@color/gm3_baseline_surface_container_highest_dark</color> <color name="tab_strip_bg_incognito">@color/gm3_baseline_surface_container_high_dark</color> <color name="tab_strip_tablet_bg_incognito">@color/gm3_baseline_surface_container_dark</color> - <color name="tab_strip_tablet_divider_bg_incognito">@color/gm3_baseline_surface_container_highest_dark</color> + <color name="tab_strip_tablet_divider_bg_incognito">@color/baseline_neutral_variant_30</color> <color name="tab_strip_tablet_bg_unfocused_incognito">@color/gm3_baseline_surface_container_low_dark</color> <color name="omnibox_suggestion_bg_hover_incognito">@color/gm3_baseline_surface_container_low_dark</color>
diff --git a/ui/views/controls/throbber.cc b/ui/views/controls/throbber.cc index bb67f6d9..869d2973 100644 --- a/ui/views/controls/throbber.cc +++ b/ui/views/controls/throbber.cc
@@ -46,9 +46,9 @@ } start_time_ = base::TimeTicks::Now(); - timer_.Start( - FROM_HERE, base::Milliseconds(GetFrameDelay(diameter_)), - base::BindRepeating(&Throbber::SchedulePaint, base::Unretained(this))); + timer_.Start(FROM_HERE, base::Milliseconds(GetFrameDelay(diameter_)), + base::BindRepeating(&Throbber::SchedulePaint, + weak_ptr_factory_.GetWeakPtr())); SchedulePaint(); // paint right away }
diff --git a/ui/views/controls/throbber.h b/ui/views/controls/throbber.h index a2f6b9b4..8d7c50f3 100644 --- a/ui/views/controls/throbber.h +++ b/ui/views/controls/throbber.h
@@ -61,6 +61,8 @@ // Overrides the default color, ui::kColorThrobber, if set. std::optional<ui::ColorId> color_id_; + + base::WeakPtrFactory<Throbber> weak_ptr_factory_{this}; }; BEGIN_VIEW_BUILDER(VIEWS_EXPORT, Throbber, View)
diff --git a/v8 b/v8 index 5110982..c59f2d9 160000 --- a/v8 +++ b/v8
@@ -1 +1 @@ -Subproject commit 5110982b4020c8303ab7aece58818cb7eaee972e +Subproject commit c59f2d912981432362352d6ae5620726d41a85cb