diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index c2ce175f..7064920 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -665,6 +665,23 @@
 59ac8227c5dd59754331b3f7f9f85e1a947f1242
 ca067f2604f9bf0ff2fa070eafeed664698d819a
 0b20ccad48bc63b0e6bf07b8511b32b8e3d963b1
+a98e4438c6229a95ecd8c5f0acebc6c95f9028b4
+74f09f8a69f0b27fda9581de477896071917256a
+c686e8f4fd379312469fe018f5c390e9c8f20d0d
+b263d258c9e4899afaa24036bde76d7e9e1d537c
+8c3a4c4fd8ddc5c8c3384f29e48932f81a38a462
+69fa1c8ea7b8b207343b91ca8db5e3e7d372b1c7
+fe132eeb21687c455d695d6af346f15454828d01
+14af2a9cdbfb78e7244d0a861babaf4388944ff1
+c571efbef3ecfe66613d524ff39c58e25d18548c
+618111ac68d8ed2e3a84eee9cae1cf61ce9ba236
+581b9e8403fdba9f33cc315c56180f841407c86b
+e795a58002fc09c3417489cf419798c8d8ab0ba3
+d2b5c17eff35da6ebff8ba20c99688b87e1bc752
+9021f6eff4a13c7c43ef3c544b7ba5ae9953dab6
+4787fce6c51383f5631643ac3d14cc512d656de6
+3eb9fd518875bee685ad2e8c2b699822a8dfd5d9
+e5fff99cbb0380ea7f44c60ee15554b6b56320fb
 
 # Reformat .java code with google-java-format. Tagged with Bug: 1491626 (part 2)
 c89f6078b3d03a07e8859e4e2be5dc9baaf1d5f0
diff --git a/.gn b/.gn
index afe0b3e..6abe8e5 100644
--- a/.gn
+++ b/.gn
@@ -76,6 +76,12 @@
 # their includes checked for proper dependencies when you run either
 # "gn check" or "gn gen --check".
 no_check_targets = [
+  # TODO(crbug.com/326607005): Remove the exceptions for googletest once it is
+  # possible to support Abseil flags in tests without regressing things (e.g.
+  # no added static initializers) in production binaries.
+  "//third_party/googletest:gmock",
+  "//third_party/googletest:gtest",
+
   # //v8, https://crbug.com/v8/7330
   "//v8/src/inspector:inspector",  # 20 errors
   "//v8/test/cctest:cctest_sources",  # 15 errors
diff --git a/AUTHORS b/AUTHORS
index 6119bcd7..e6438da3 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -53,6 +53,7 @@
 Ajay Sharma <ajay.sh@samsung.com>
 Ajith Kumar V <ajith.v@samsung.com>
 Akash Yadav <akash1.yadav@samsung.com>
+Akihiko Odaki <akihiko.odaki@gmail.com>
 Akos Kiss <akiss@inf.u-szeged.hu>
 Aku Kotkavuo <a.kotkavuo@partner.samsung.com>
 Aldo Culquicondor <alculquicondor@gmail.com>
diff --git a/DEPS b/DEPS
index 51578d1..8f4cbf7 100644
--- a/DEPS
+++ b/DEPS
@@ -288,7 +288,7 @@
   'sysroots_json_path': 'build/linux/sysroot_scripts/sysroots.json',
 
   # siso CIPD package version.
-  'siso_version': 'git_revision:b52a6552a2e17e34b747fd5d29875fc4aba99da8',
+  'siso_version': 'git_revision:8632c71c8cadd9cb9ea4d43e6b30eeae4dffcd12',
 
   # download libaom test data
   'download_libaom_testdata': False,
@@ -308,27 +308,27 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'src_internal_revision': 'ad2b19f04fe915ec0cdbac9830e7c5254b055cd7',
+  'src_internal_revision': '5798a096a03a88db5e3a14645bd747d811dbd560',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'f94b35f33a8277de713a2aafc64b26a241e2ab12',
+  'skia_revision': '2e47b3ccb65fe6ca0c84f4f6b6ffc33f243247c3',
   # 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': 'a2047bfab691438574d4485d96d2c3c006371877',
+  'v8_revision': 'c5526930f87c21bd0994e7cdbb589c5c5510c112',
   # 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': 'acba61cb3e27f15b56ca781813efa357b9ca0f1f',
+  'angle_revision': '9100f2ec79ec11f024b9729fe26f45470f66ba8f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': '0f69b790c7a491e103802870b2f670c5936b9930',
+  'swiftshader_revision': 'bbe6452b420c5ddc4b0fd421b0a3ce271262f4ca',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '88eff81cca5902a687e4fc4cfbec03d293c200f3',
+  'pdfium_revision': 'f1805084d8ec1a854ffa6e4f3d489aaa5c9818ab',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -339,7 +339,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Fuchsia sdk
   # and whatever else without interference from each other.
-  'fuchsia_version': 'version:18.20240215.1.1',
+  'fuchsia_version': '18.20240215.1.1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling google-toolbox-for-mac
   # and whatever else without interference from each other.
@@ -347,7 +347,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling googletest
   # and whatever else without interference from each other.
-  'googletest_revision': 'af29db7ec28d6df1c7f0f745186884091e602e07',
+  'googletest_revision': '76bb2afb8b522d24496ad1c757a49784fbfa2e42',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling lighttpd
   # and whatever else without interference from each other.
@@ -383,11 +383,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '4dc7721a144450da73f9adc3abcff225c804ff3f',
+  'catapult_revision': '6f4a0d6c8731078f74f3de4fc92748c125da43d6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling chromium_variations
   # and whatever else without interference from each other.
-  'chromium_variations_revision': '04c3d68a4e1c34c789ad6b50e2b00960a4e9bc3c',
+  'chromium_variations_revision': '1fae85ca70bdf203941f8ac90392e7d471247147',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling CrossBench
   # and whatever else without interference from each other.
@@ -399,11 +399,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling fuzztest
   # and whatever else without interference from each other.
-  'fuzztest_revision': '61d95200e7ece7d121cab26f0c39fbf392e6566e',
+  'fuzztest_revision': 'bddcd9f77ba0a81a99ce50bcadf5149efe545df0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': '0eb688bd504b2b3fdf5ea8adc8975afbda2e18bf',
+  'devtools_frontend_revision': '5ccdd75fa57a758fa15db394dd6ad6092963cfed',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -427,7 +427,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '8e33c32682850534d81a0b511261a94ff312978c',
+  'dawn_revision': 'fd97e964d72ca376aa380fc0bbeca886674f45ed',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -479,7 +479,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'libcxxabi_revision':    'a7b3d968a3a923886fea64b424bd770e69dc4ea4',
+  'libcxxabi_revision':    '5b35c9f06c3f8f17b43bd3da9527d6fecdf916c2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -499,14 +499,14 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling beto-core
   # and whatever else without interference from each other.
-  'betocore_revision': '4d202dab960a0b6a6e4757ab4393945aca5a09db',
+  'betocore_revision': 'bd1f1272cd2a6605ec793b914ada2c4ebcc820f6',
 
   # If you change this, also update the libc++ revision in
   # //buildtools/deps_revisions.gni.
-  'libcxx_revision':       '5a3d13ed42814e59d9b947a8fae826537116b3ee',
+  'libcxx_revision':       '08b8dfd3a9689085f0b0aa0f3e5912e88e5d4ac6',
 
   # GN CIPD package version.
-  'gn_version': 'git_revision:03d10f1657b4ddace618c34ab61b6357d1ae9c9a',
+  'gn_version': 'git_revision:5787e994aa4cb6cdb09c2c72ae6f1c6a7f1cf91a',
 
   # ninja CIPD package version.
   # https://chrome-infra-packages.appspot.com/p/infra/3pp/tools/ninja
@@ -827,12 +827,12 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '1b97a7f4cc5e80f931ec9a2b90253a17735ad7fe',
+    '6c7e651daf6bfddb87ebe2e63f0dc93b28aebf6a',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
   'src/docs/website': {
-    'url': Var('chromium_git') + '/website.git' + '@' + '254fa7bcc05c8aa095289dc84db750efbcdae37e',
+    'url': Var('chromium_git') + '/website.git' + '@' + 'ecc6daec0bc6bc14edaad139f726d7a0154d4572',
   },
 
   'src/ios/third_party/earl_grey2/src': {
@@ -989,7 +989,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 't9WCSa3pyfLqHhv8_577tLFVY-ANlLru3HBHLPHdgAAC',
+          'version': 'unO3_k1jYtik0aRkumx_4IMBQoCIfx4yAcgeqnLPvugC',
       },
     ],
     'condition': 'checkout_android',
@@ -1164,7 +1164,7 @@
   # Tools used when building Chrome for Chrome OS. This affects both the Simple
   # Chrome workflow, as well as the chromeos-chrome ebuild.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '070f3e0e65725de8f8d3f14a6e46ed7e0e911a45',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '21c56f5c330bab014098f49c6d5b9f2f9cba3473',
       'condition': 'checkout_chromeos',
   },
 
@@ -1178,14 +1178,14 @@
     Var('chromium_git') + '/external/github.com/google/cpu_features.git' + '@' + '936b9ab5515dead115606559502e3864958f7f6e',
 
   'src/third_party/cpuinfo/src':
-    Var('chromium_git') + '/external/github.com/pytorch/cpuinfo.git' + '@' + '9484a6c590f831a30c1eec1311568b1a967a89dc',
+    Var('chromium_git') + '/external/github.com/pytorch/cpuinfo.git' + '@' + 'aa4b2163b99ac9534194520f70b93eeefb0b3b4e',
 
   'src/third_party/crc32c/src':
     Var('chromium_git') + '/external/github.com/google/crc32c.git' + '@' + 'fa5ade41ee480003d9c5af6f43567ba22e4e17e6',
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'd2229e09bc30d6ceab275991e26a9f3b1d5a74c0',
+      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '422a282c95ed618b6401d1e05bba6808bcfc8173',
       'condition': 'checkout_linux or checkout_chromeos',
   },
 
@@ -1199,13 +1199,13 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'cb43b5d82d72ae1fddb56ce9a9092d0438ff0cd9',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '4df61147ba67316806617f74347f408d2e4ff2f1',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
 
   'src/third_party/devtools-frontend-internal': {
-      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '88eb78cfb6b9ddc20128ffb9674b0ce81c593ca4',
+      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '2173cbdf60dac9a327293104c19c93e63a3e46ee',
     'condition': 'checkout_src_internal',
   },
 
@@ -1213,7 +1213,7 @@
     Var('chromium_git') + '/chromium/dom-distiller/dist.git' + '@' + '199de96b345ada7c6e7e6ba3d2fa7a6911b8767d',
 
   'src/third_party/eigen3/src':
-    Var('chromium_git') + '/external/gitlab.com/libeigen/eigen.git' + '@' + '7fd7a3f946e5ac152d28dad388cff8bfa1026925',
+    Var('chromium_git') + '/external/gitlab.com/libeigen/eigen.git' + '@' + '2a9055b50ed22101da7d77e999b90ed50956fe0b',
 
   'src/third_party/emoji-metadata/src': {
     'url': Var('chromium_git') + '/external/github.com/googlefonts/emoji-metadata' + '@' + '045f146fca682a836e01cd265171312bfb300e06',
@@ -1533,7 +1533,7 @@
   },
 
   'src/third_party/libvpx/source/libvpx':
-    Var('chromium_git') + '/webm/libvpx.git' + '@' +  '3316c11240184851f8ce1c3061db8e22123cf9ed',
+    Var('chromium_git') + '/webm/libvpx.git' + '@' +  'd191c5f98454f544df501fa41999ba24b5cf171b',
 
   'src/third_party/libwebm/source':
     Var('chromium_git') + '/webm/libwebm.git' + '@' + 'e4fbea0c9751ae8aa86629b197a28d8276a2b0da',
@@ -1665,7 +1665,7 @@
     Var('pdfium_git') + '/pdfium.git' + '@' +  Var('pdfium_revision'),
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '4183dabcac163845c7207da5d1d8a6e3927b95dc',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '2778513f999795da191e124162f74a30dd6680c4',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '8ef97ff3b7332e38e61b347a2fbed425a4617151',
@@ -1797,20 +1797,20 @@
     Var('chromium_git') + '/external/github.com/GoogleChromeLabs/text-fragments-polyfill.git' + '@' + 'c036420683f672d685e27415de0a5f5e85bdc23f',
 
   'src/third_party/tflite/src':
-    Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + 'e4ddf94e92d72ce34de2f45f036e29678a9527f7',
+    Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + '2d13600b56f64da95e9499a1bf95c735699858f0',
 
   'src/third_party/turbine': {
       'packages': [
           {
               'package': 'chromium/third_party/turbine',
-              'version': 's-hdujub30RR2mH9Qf7pHv6h9uNGEiYVs6W1VXWeEe8C',
+              'version': 'ZsrSMKpQt5d43K50XC1both1bFWzoloH6xOKYKZK_64C',
           },
       ],
       'condition': 'checkout_android',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@fda3fc86e76347dc8d1df07d68aec006c98974d9',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@56b277ab9762b2f286010d7ba27c9c07131f712e',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '56300b29fbfcc693ee6609ddad3fdd5b7a449a21',
@@ -1847,10 +1847,10 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'f4bf599a8b575df685c31d9c4729a70a04e377ed',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '8dc82d09a9c69d4ea8e3227a75713e8c27365c15',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '98673cc24786be6c10dd8908e0b0b4ed27625c6a',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'ff0c960ee791fe1c816994c29f6b6d173690fd08',
+    Var('webrtc_git') + '/src.git' + '@' + '51532fd3554fc47c0d1087dc008e7b4fb99a7287',
 
   # Wuffs' canonical repository is at github.com/google/wuffs, but we use
   # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file.
@@ -1875,7 +1875,7 @@
   },
 
   'src/third_party/xnnpack/src':
-    Var('chromium_git') + '/external/github.com/google/XNNPACK.git' + '@' + '9325fcfe52092b2f8f816db218bca208db7b2750',
+    Var('chromium_git') + '/external/github.com/google/XNNPACK.git' + '@' + '3673b5777ef2c350558bac8c630fbffc74a3be25',
 
   'src/tools/page_cycler/acid3':
     Var('chromium_git') + '/chromium/deps/acid3.git' + '@' + 'a926d0a32e02c4c03ae95bb798e6c780e0e184ba',
@@ -1894,7 +1894,7 @@
   },
 
   'src/third_party/zstd/src':
-    Var('chromium_git') + '/external/github.com/facebook/zstd.git' + '@' + '050fec5c378d676fede8b2171ec5e84f6afa1504',
+    Var('chromium_git') + '/external/github.com/facebook/zstd.git' + '@' + '621a263fb2e6c2175fbd489e5d77ee8038baa2b2',
 
   'src/tools/skia_goldctl/linux': {
       'packages': [
@@ -1962,7 +1962,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/eche_app/app',
-        'version': 'hIJPWhPJNyRu_n8XR62Kqb7RQ5NfwnREHEvZ6I-TLR0C',
+        'version': 'rUa1DCKTowD-CVyTwB4OITTMTuQ9zHyQ0iOjFRDHb-8C',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1973,7 +1973,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': 'vlCZ6O7FpsQbXF3c7-wdjpidNElu0vp_6XuH6hrC9v8C',
+        'version': '_g6MJUUrZNM_z2GjotgMlXISlMyDJcGAc-DMXOMBKkgC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1984,7 +1984,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'NnD_TAM5Gh2pqIw9zcN0qm-zishL0eJJpozX0hWOpncC',
+        'version': 'iwZSBgY1X8nMG8at7xFZwtMPqU7_WP0TYJ9lYby1gCwC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -2017,7 +2017,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/projector_app/app',
-        'version': 'z8XITk6bX7sZL2pROlKAxCt4CLgYdKLtFhDnfxz0bJEC',
+        'version': 'iMf3-gy5BU1wc0TqU3UuS0qDM_HgBLtLgqUVbxM0jasC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -4036,7 +4036,7 @@
 
   'src/components/optimization_guide/internal': {
       'url': Var('chrome_git') + '/chrome/components/optimization_guide.git' + '@' +
-        'a7fe2c3fbd37e5e2a4cce41f38d7dbd395313d91',
+        '3e87b5cf956eeb1cfc3437ae5dd09e86cacbf9f9',
       'condition': 'checkout_src_internal',
   },
 
@@ -4096,7 +4096,7 @@
 
   'src/ios_internal':  {
       'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' +
-        'ec7715a343c234698035f588ce7c300a5dbf89ce',
+        '2e41c6955ac16c3568e2e0b1685e08fd689addb9',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 127552b..cab2347 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -1308,6 +1308,18 @@
       [_THIRD_PARTY_EXCEPT_BLINK],  # Don't warn in third_party folders.
     ),
     BanRule(
+      r'/\bstd::to_address\b',
+      (
+        'std::to_address is banned because it is not guaranteed to be',
+        'SFINAE-compatible. Use base::to_address instead.',
+      ),
+      True,
+      [
+        # Needed in base::to_address implementation.
+        r'base/types/to_address.h',
+        _THIRD_PARTY_EXCEPT_BLINK],  # Not an error in third_party folders.
+    ),
+    BanRule(
       r'/#include <syncstream>',
       (
         '<syncstream> is banned.',
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index f287505..76f5594 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -528,6 +528,7 @@
     "java/src/org/chromium/android_webview/AwDevToolsServer.java",
     "java/src/org/chromium/android_webview/AwFeatureMap.java",
     "java/src/org/chromium/android_webview/AwHttpAuthHandler.java",
+    "java/src/org/chromium/android_webview/AwInterfaceRegistrar.java",
     "java/src/org/chromium/android_webview/AwPacProcessor.java",
     "java/src/org/chromium/android_webview/AwPdfExporter.java",
     "java/src/org/chromium/android_webview/AwProxyController.java",
@@ -588,6 +589,7 @@
     "java/src/org/chromium/android_webview/AwGeolocationPermissions.java",
     "java/src/org/chromium/android_webview/AwHistogramRecorder.java",
     "java/src/org/chromium/android_webview/AwHttpAuthHandler.java",
+    "java/src/org/chromium/android_webview/AwInterfaceRegistrar.java",
     "java/src/org/chromium/android_webview/AwKeyboardShortcuts.java",
     "java/src/org/chromium/android_webview/AwLayoutSizer.java",
     "java/src/org/chromium/android_webview/AwMediaIntegrityApiStatusConfig.java",
@@ -705,6 +707,7 @@
     "//components/embedder_support/android:util_java",
     "//components/embedder_support/android:web_contents_delegate_java",
     "//components/embedder_support/android/metrics:java",
+    "//components/externalauth/android:google_delegate_public_impl_java",
     "//components/minidump_uploader:minidump_uploader_java",
     "//components/navigation_interception/android:navigation_interception_java",
     "//components/policy/android:policy_java",
@@ -714,22 +717,27 @@
     "//components/variations:variations_java",
     "//components/variations/android:variations_java",
     "//components/viz/service:service_java",
+    "//components/webauthn/android:delegate_public_java",
+    "//components/webauthn/android:java",
     "//components/zoom/android:java",
     "//content/public/android:content_java",
     "//content/public/android:content_java_resources",
     "//content/public/common:common_java",
     "//device/gamepad:java",
+    "//mojo/public/java:bindings_java",
     "//mojo/public/java:system_java",
     "//mojo/public/java/system:system_impl_java",
     "//net/android:net_java",
     "//services/data_decoder/public/cpp/android:safe_json_java",
     "//services/network/public/mojom:mojom_java",
     "//services/network/public/mojom:url_loader_base_java",
+    "//services/service_manager/public/java:service_manager_java",
     "//third_party/android_deps:com_google_code_findbugs_jsr305_java",
     "//third_party/android_deps:protobuf_lite_runtime_java",
     "//third_party/androidx:androidx_annotation_annotation_java",
     "//third_party/androidx:androidx_core_core_java",
     "//third_party/blink/public:blink_headers_java",
+    "//third_party/blink/public/mojom:android_mojo_bindings_java",
     "//third_party/blink/public/mojom:mojom_platform_java",
     "//third_party/jni_zero:jni_zero_java",
     "//third_party/metrics_proto:metrics_proto_java",
diff --git a/android_webview/browser/BUILD.gn b/android_webview/browser/BUILD.gn
index abf0b22..c80183a 100644
--- a/android_webview/browser/BUILD.gn
+++ b/android_webview/browser/BUILD.gn
@@ -304,6 +304,8 @@
     "//content/public/browser",
     "//media/mojo:buildflags",
     "//services/cert_verifier/public/mojom",
+    "//services/device/public/cpp:device_feature_list",
+    "//services/device/public/java:device_feature_list_jni",
     "//services/network/public/mojom",
     "//services/proxy_resolver:lib",
     "//third_party/blink/public/common",
diff --git a/android_webview/browser/aw_browser_context_store.cc b/android_webview/browser/aw_browser_context_store.cc
index fe911b70..850b2e1 100644
--- a/android_webview/browser/aw_browser_context_store.cc
+++ b/android_webview/browser/aw_browser_context_store.cc
@@ -13,6 +13,7 @@
 #include "android_webview/browser/aw_browser_process.h"
 #include "android_webview/browser_jni_headers/AwBrowserContextStore_jni.h"
 #include "base/check_op.h"
+#include "base/feature_list.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/memory/raw_ptr.h"
@@ -26,6 +27,7 @@
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_process_host.h"
 
 namespace android_webview {
 
@@ -36,6 +38,14 @@
 
 bool g_initialized = false;
 
+BASE_FEATURE(kCreateSpareRendererOnBrowserContextCreation,
+             "CreateSpareRendererOnBrowserContextCreation",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+const base::FeatureParam<bool> kCreateSpareRendereForDefaultIfMultiProfile{
+    &kCreateSpareRendererOnBrowserContextCreation,
+    "create_spare_renderer_for_default_if_multi_profile", true};
+
 }  // namespace
 
 AwBrowserContextStore::AwBrowserContextStore(PrefService* pref_service)
@@ -101,6 +111,16 @@
     const bool is_default = name == kDefaultContextName;
     entry->instance =
         std::make_unique<AwBrowserContext>(name, entry->path, is_default);
+    // Ensure this code path is only taken if the IO thread is already running,
+    // as it's needed for launching processes.
+    if (base::FeatureList::IsEnabled(
+            kCreateSpareRendererOnBrowserContextCreation) &&
+        content::BrowserThread::IsThreadInitialized(
+            content::BrowserThread::IO) &&
+        (!is_default || kCreateSpareRendereForDefaultIfMultiProfile.Get())) {
+      content::RenderProcessHost::WarmupSpareRenderProcessHost(
+          entry->instance.get());
+    }
   }
   return entry->instance.get();
 }
diff --git a/android_webview/browser/aw_browser_main_parts.cc b/android_webview/browser/aw_browser_main_parts.cc
index d46b3ca..8e72060c 100644
--- a/android_webview/browser/aw_browser_main_parts.cc
+++ b/android_webview/browser/aw_browser_main_parts.cc
@@ -18,6 +18,7 @@
 #include "android_webview/browser/metrics/system_state_util.h"
 #include "android_webview/browser/network_service/aw_network_change_notifier_factory.h"
 #include "android_webview/browser/tracing/background_tracing_field_trial.h"
+#include "android_webview/browser_jni_headers/AwInterfaceRegistrar_jni.h"
 #include "android_webview/common/aw_descriptors.h"
 #include "android_webview/common/aw_paths.h"
 #include "android_webview/common/aw_resource.h"
@@ -315,6 +316,9 @@
   // to load the database from disk.
   AwBrowserContext::GetDefault()->GetOriginTrialsControllerDelegate();
 
+  Java_AwInterfaceRegistrar_registerMojoInterfaces(
+      base::android::AttachCurrentThread());
+
   return content::RESULT_CODE_NORMAL_EXIT;
 }
 
diff --git a/android_webview/browser/aw_contents_io_thread_client.cc b/android_webview/browser/aw_contents_io_thread_client.cc
index d299db1..da0ae21 100644
--- a/android_webview/browser/aw_contents_io_thread_client.cc
+++ b/android_webview/browser/aw_contents_io_thread_client.cc
@@ -22,6 +22,7 @@
 #include "base/functional/bind.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
+#include "base/memory/raw_ptr.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/scoped_blocking_call.h"
@@ -57,7 +58,8 @@
 typedef map<content::GlobalRenderFrameHostToken, JavaObjectWeakGlobalRef>
     RenderFrameHostToWeakGlobalRefType;
 
-typedef pair<base::flat_set<RenderFrameHost*>, JavaObjectWeakGlobalRef>
+typedef pair<base::flat_set<raw_ptr<RenderFrameHost, CtnExperimental>>,
+             JavaObjectWeakGlobalRef>
     HostsAndWeakGlobalRefPair;
 
 // When browser side navigation is enabled, RenderFrameIDs do not have
diff --git a/android_webview/java/DEPS b/android_webview/java/DEPS
index e00b811..f39c800 100644
--- a/android_webview/java/DEPS
+++ b/android_webview/java/DEPS
@@ -8,6 +8,7 @@
   "+components/safe_browsing/android/java",
   "+components/stylus_handwriting/android/java",
   "+components/component_updater/android/java",
+  "+components/webauthn/android",
   "+components/zoom/android/java",
 
   "-content/public/android/java",
diff --git a/android_webview/java/src/org/chromium/android_webview/AwInterfaceRegistrar.java b/android_webview/java/src/org/chromium/android_webview/AwInterfaceRegistrar.java
new file mode 100644
index 0000000..6515e050
--- /dev/null
+++ b/android_webview/java/src/org/chromium/android_webview/AwInterfaceRegistrar.java
@@ -0,0 +1,33 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.android_webview;
+
+import org.jni_zero.CalledByNative;
+
+import org.chromium.blink.mojom.Authenticator;
+import org.chromium.components.webauthn.AuthenticatorFactory;
+import org.chromium.content_public.browser.InterfaceRegistrar;
+import org.chromium.content_public.browser.RenderFrameHost;
+import org.chromium.services.service_manager.InterfaceRegistry;
+
+/** Registers mojo interface implementations exposed to C++ code at the Android Webview layer. */
+class AwInterfaceRegistrar {
+    @CalledByNative
+    private static void registerMojoInterfaces() {
+        InterfaceRegistrar.Registry.addRenderFrameHostRegistrar(
+                new AndroidWebviewRenderFrameHostInterfaceRegistrar());
+    }
+
+    private static class AndroidWebviewRenderFrameHostInterfaceRegistrar
+            implements InterfaceRegistrar<RenderFrameHost> {
+        @Override
+        public void registerInterfaces(
+                InterfaceRegistry registry, final RenderFrameHost renderFrameHost) {
+            registry.addInterface(
+                    Authenticator.MANAGER,
+                    new AuthenticatorFactory(renderFrameHost, /* confirmationFactory= */ null));
+        }
+    }
+}
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 10311bb2..cd6dff6e 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
@@ -427,10 +427,6 @@
                 "Enables establishing the GPU channel asnchronously when requesting a new "
                         + "layer tree frame sink."),
         Flag.baseFeature(
-                BlinkFeatures.DECODE_SCRIPT_SOURCE_OFF_THREAD,
-                "If enabled, script source text will be decoded and hashed off the main"
-                        + "thread."),
-        Flag.baseFeature(
                 BaseFeatures.OPTIMIZE_DATA_URLS, "Optimizes parsing and loading of data: URLs."),
         Flag.baseFeature(
                 BlinkFeatures.PREFETCH_FONT_LOOKUP_TABLES,
@@ -907,6 +903,11 @@
                 "DoNotEvictOnAXLocationChange",
                 "When enabled, do not evict the bfcache entry even when AXLocationChange happens."),
         Flag.baseFeature("PassHistogramSharedMemoryOnLaunch"),
+        Flag.baseFeature(
+                BlinkFeatures.NO_THROTTLING_VISIBLE_AGENT,
+                "Do not throttle Javascript timers to 1Hz on hidden cross-origin frames that are"
+                        + " same-agent with a visible frame."),
+        Flag.baseFeature("CreateSpareRendererOnBrowserContextCreation"),
         // Add new commandline switches and features above. The final entry should have a
         // trailing comma for cleaner diffs.
     };
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwAutofillTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwAutofillTest.java
index aefb166..ba653dd 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwAutofillTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwAutofillTest.java
@@ -96,16 +96,18 @@
     public static final int AUTOFILL_VIEW_EXITED = 1;
     public static final int AUTOFILL_VALUE_CHANGED = 2;
     public static final int AUTOFILL_COMMIT = 3;
-    public static final int AUTOFILL_CANCEL = 4;
-    public static final int AUTOFILL_SESSION_STARTED = 5;
-    public static final int AUTOFILL_PREDICTIONS_AVAILABLE = 6;
-    public static final int AUTOFILL_EVENT_MAX = 7;
+    public static final int AUTOFILL_CANCEL_PRE_P = 4;
+    public static final int AUTOFILL_CANCEL = 5;
+    public static final int AUTOFILL_SESSION_STARTED = 6;
+    public static final int AUTOFILL_PREDICTIONS_AVAILABLE = 7;
+    public static final int AUTOFILL_EVENT_MAX = 8;
 
     public static final String[] EVENT = {
         "VIEW_ENTERED",
         "VIEW_EXITED",
         "VALUE_CHANGED",
         "COMMIT",
+        "CANCEL_PRE_P",
         "CANCEL",
         "SESSION_STARTED",
         "QUERY_DONE"
@@ -183,7 +185,6 @@
             mEventQueue.add(AUTOFILL_CANCEL);
             mCallbackHelper.notifyCalled();
         }
-
         @Override
         public void notifyNewSessionStarted(boolean hasServerPrediction) {
             if (DEBUG) Log.i(TAG, "notifyNewSessionStarted");
@@ -259,7 +260,7 @@
                     mTest.waitForCallbackAndVerifyTypes(
                             mCnt,
                             new Integer[] {
-                                AUTOFILL_CANCEL,
+                                AUTOFILL_CANCEL_PRE_P,
                                 AUTOFILL_VIEW_ENTERED,
                                 AUTOFILL_SESSION_STARTED,
                                 AUTOFILL_VALUE_CHANGED
@@ -277,7 +278,7 @@
                     mTest.waitForCallbackAndVerifyTypes(
                             mCnt,
                             new Integer[] {
-                                AUTOFILL_CANCEL,
+                                AUTOFILL_CANCEL_PRE_P,
                                 AUTOFILL_VIEW_ENTERED,
                                 AUTOFILL_SESSION_STARTED,
                                 AUTOFILL_VALUE_CHANGED
@@ -325,7 +326,10 @@
             mTest.executeJavaScriptAndWaitForResult("document.getElementById('formid').submit();");
             mCnt +=
                     mTest.waitForCallbackAndVerifyTypes(
-                            mCnt, new Integer[] {AUTOFILL_VALUE_CHANGED, AUTOFILL_COMMIT});
+                            mCnt,
+                            new Integer[] {
+                                AUTOFILL_VALUE_CHANGED, AUTOFILL_COMMIT, AUTOFILL_CANCEL
+                            });
         }
 
         public void reload() throws Throwable {
@@ -334,7 +338,10 @@
                     mTest.waitForCallbackAndVerifyTypes(
                             mCnt,
                             new Integer[] {
-                                AUTOFILL_VIEW_EXITED, AUTOFILL_VALUE_CHANGED, AUTOFILL_COMMIT
+                                AUTOFILL_VIEW_EXITED,
+                                AUTOFILL_VALUE_CHANGED,
+                                AUTOFILL_COMMIT,
+                                AUTOFILL_CANCEL
                             });
         }
 
@@ -347,7 +354,7 @@
                             mCnt,
                             new Integer[] {
                                 AUTOFILL_VIEW_EXITED,
-                                AUTOFILL_CANCEL,
+                                AUTOFILL_CANCEL_PRE_P,
                                 AUTOFILL_VIEW_ENTERED,
                                 AUTOFILL_SESSION_STARTED,
                                 AUTOFILL_VALUE_CHANGED
@@ -479,7 +486,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_SESSION_STARTED
+                            AUTOFILL_CANCEL_PRE_P, AUTOFILL_VIEW_ENTERED, AUTOFILL_SESSION_STARTED
                         });
         dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
         waitForCallbackAndVerifyTypes(cnt, new Integer[] {AUTOFILL_VALUE_CHANGED});
@@ -519,7 +526,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -674,7 +681,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VIEW_EXITED,
@@ -740,7 +747,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_SESSION_STARTED
+                            AUTOFILL_CANCEL_PRE_P, AUTOFILL_VIEW_ENTERED, AUTOFILL_SESSION_STARTED
                         });
 
         // Reload the page and check that the user clicking on the same form field ends the current
@@ -755,6 +762,7 @@
                         new Integer[] {
                             AUTOFILL_VIEW_EXITED,
                             AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED
                         });
@@ -774,7 +782,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -809,7 +817,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -857,7 +865,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -909,7 +917,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -972,7 +980,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -1023,7 +1031,8 @@
                     AUTOFILL_VALUE_CHANGED,
                     AUTOFILL_VALUE_CHANGED,
                     AUTOFILL_VALUE_CHANGED,
-                    AUTOFILL_COMMIT
+                    AUTOFILL_COMMIT,
+                    AUTOFILL_CANCEL
                 });
         ArrayList<Pair<Integer, AutofillValue>> values = getChangedValues();
         assertEquals(4, values.size());
@@ -1046,7 +1055,7 @@
         waitForCallbackAndVerifyTypes(
                 cnt,
                 new Integer[] {
-                    AUTOFILL_CANCEL,
+                    AUTOFILL_CANCEL_PRE_P,
                     AUTOFILL_VIEW_ENTERED,
                     AUTOFILL_SESSION_STARTED,
                     AUTOFILL_VALUE_CHANGED
@@ -1078,7 +1087,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -1090,7 +1099,7 @@
                 cnt,
                 new Integer[] {
                     AUTOFILL_VIEW_EXITED,
-                    AUTOFILL_CANCEL,
+                    AUTOFILL_CANCEL_PRE_P,
                     AUTOFILL_VIEW_ENTERED,
                     AUTOFILL_SESSION_STARTED,
                     AUTOFILL_VALUE_CHANGED
@@ -1163,7 +1172,7 @@
                 waitForCallbackAndVerifyTypes(
                         count,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -1182,7 +1191,7 @@
                 count,
                 new Integer[] {
                     AUTOFILL_VIEW_EXITED,
-                    AUTOFILL_CANCEL,
+                    AUTOFILL_CANCEL_PRE_P,
                     AUTOFILL_VIEW_ENTERED,
                     AUTOFILL_SESSION_STARTED,
                     AUTOFILL_VALUE_CHANGED
@@ -1217,7 +1226,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_SESSION_STARTED
+                            AUTOFILL_CANCEL_PRE_P, AUTOFILL_VIEW_ENTERED, AUTOFILL_SESSION_STARTED
                         });
     }
 
@@ -1247,7 +1256,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_SESSION_STARTED
+                            AUTOFILL_CANCEL_PRE_P, AUTOFILL_VIEW_ENTERED, AUTOFILL_SESSION_STARTED
                         });
 
         // Removing focus from this element should cause a notification that the autofill view was
@@ -1293,7 +1302,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -1305,7 +1314,8 @@
                     AUTOFILL_VIEW_EXITED,
                     AUTOFILL_VALUE_CHANGED,
                     AUTOFILL_VALUE_CHANGED,
-                    AUTOFILL_COMMIT
+                    AUTOFILL_COMMIT,
+                    AUTOFILL_CANCEL
                 });
         assertEquals(SubmissionSource.PROBABLY_FORM_SUBMITTED, mSubmissionSource);
     }
@@ -1356,7 +1366,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -1403,7 +1413,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -1453,7 +1463,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -1496,7 +1506,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -1535,7 +1545,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -2176,7 +2186,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -2188,7 +2198,10 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_VIEW_EXITED, AUTOFILL_VALUE_CHANGED, AUTOFILL_COMMIT
+                            AUTOFILL_VIEW_EXITED,
+                            AUTOFILL_VALUE_CHANGED,
+                            AUTOFILL_COMMIT,
+                            AUTOFILL_CANCEL
                         });
 
         TestThreadUtils.runOnUiThreadBlocking(
@@ -2229,7 +2242,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -2243,7 +2256,10 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_VIEW_EXITED, AUTOFILL_VALUE_CHANGED, AUTOFILL_COMMIT
+                            AUTOFILL_VIEW_EXITED,
+                            AUTOFILL_VALUE_CHANGED,
+                            AUTOFILL_COMMIT,
+                            AUTOFILL_CANCEL
                         });
 
         TestThreadUtils.runOnUiThreadBlocking(
@@ -2280,7 +2296,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -2300,7 +2316,10 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_VIEW_EXITED, AUTOFILL_VALUE_CHANGED, AUTOFILL_COMMIT
+                            AUTOFILL_VIEW_EXITED,
+                            AUTOFILL_VALUE_CHANGED,
+                            AUTOFILL_COMMIT,
+                            AUTOFILL_CANCEL
                         });
 
         TestThreadUtils.runOnUiThreadBlocking(
@@ -2386,7 +2405,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -2425,7 +2444,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -2458,7 +2477,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -2499,7 +2518,7 @@
         // datalist.
         cnt +=
                 waitForCallbackAndVerifyTypes(
-                        cnt, new Integer[] {AUTOFILL_CANCEL, AUTOFILL_SESSION_STARTED});
+                        cnt, new Integer[] {AUTOFILL_CANCEL_PRE_P, AUTOFILL_SESSION_STARTED});
         // Verify input accepted.
         String value1 =
                 executeJavaScriptAndWaitForResult("document.getElementById('text2').value;");
@@ -2563,7 +2582,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -2606,7 +2625,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -2690,7 +2709,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -2795,7 +2814,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -2858,7 +2877,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -2949,7 +2968,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -3035,7 +3054,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -3130,7 +3149,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -3192,7 +3211,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -3273,7 +3292,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -3283,7 +3302,8 @@
                     var iframe = document.getElementById('address_iframe');
                     var frame_doc = iframe.contentDocument;
                     frame_doc.getElementById('submit_button').click();""");
-        waitForCallbackAndVerifyTypes(cnt, new Integer[] {AUTOFILL_VALUE_CHANGED, AUTOFILL_COMMIT});
+        waitForCallbackAndVerifyTypes(
+                cnt, new Integer[] {AUTOFILL_VALUE_CHANGED, AUTOFILL_COMMIT, AUTOFILL_CANCEL});
         assertEquals(SubmissionSource.FORM_SUBMISSION, mSubmissionSource);
     }
 
@@ -3332,7 +3352,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -3368,7 +3388,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
                             AUTOFILL_VALUE_CHANGED
@@ -3382,7 +3402,7 @@
                 waitForCallbackAndVerifyTypes(
                         cnt,
                         new Integer[] {
-                            AUTOFILL_CANCEL,
+                            AUTOFILL_CANCEL_PRE_P,
                             AUTOFILL_VIEW_EXITED,
                             AUTOFILL_VIEW_ENTERED,
                             AUTOFILL_SESSION_STARTED,
@@ -3509,17 +3529,21 @@
     private int waitForCallbackAndVerifyTypes(int currentCallCount, Integer[] expectedEventArray)
             throws TimeoutException {
         Integer[] adjustedEventArray;
-        // Didn't call cancel after Android P.
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
-            ArrayList<Integer> adjusted = new ArrayList<Integer>();
+        ArrayList<Integer> adjusted = new ArrayList<>();
             for (Integer event : expectedEventArray) {
-                if (event != AUTOFILL_CANCEL) adjusted.add(event);
+            // Filter out AUTOFILL_CANCEL_PRE_P.
+            // TODO(b/326551145): clean that up once we stop supporting android O.
+            if (event == AUTOFILL_CANCEL_PRE_P) {
+                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
+                    adjusted.add(AUTOFILL_CANCEL);
+                }
+                continue;
             }
-            adjustedEventArray = new Integer[adjusted.size()];
-            adjusted.toArray(adjustedEventArray);
-        } else {
-            adjustedEventArray = expectedEventArray;
+            adjusted.add(event);
         }
+
+        adjustedEventArray = new Integer[adjusted.size()];
+        adjusted.toArray(adjustedEventArray);
         try {
             // Check against the call count to avoid missing out a callback in between waits, while
             // exposing it so that the test can control where the call count starts.
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientOnRenderProcessGoneTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientOnRenderProcessGoneTest.java
index a513b12..e9ee506 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientOnRenderProcessGoneTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientOnRenderProcessGoneTest.java
@@ -164,6 +164,7 @@
 
     @Test
     @Feature({"AndroidWebView"})
+    @CommandLineFlags.Add({"disable-features=CreateSpareRendererOnBrowserContextCreation"})
     @SmallTest
     @OnlyRunIn(MULTI_PROCESS)
     public void testRenderProcessCanNotTerminateBeforeStart() throws Throwable {
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwMetricsIntegrationTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwMetricsIntegrationTest.java
index b6f6edb..9bbaba1 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwMetricsIntegrationTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwMetricsIntegrationTest.java
@@ -325,6 +325,7 @@
     @Test
     @MediumTest
     @Feature({"AndroidWebView"})
+    @CommandLineFlags.Add({"disable-features=CreateSpareRendererOnBrowserContextCreation"})
     public void testMetadata_stability_rendererLaunchCount() throws Throwable {
         EmbeddedTestServer embeddedTestServer =
                 EmbeddedTestServer.createAndStartServer(
diff --git a/android_webview/test/shell/src/draw_fn/context_manager.cc b/android_webview/test/shell/src/draw_fn/context_manager.cc
index 41c6281..85de00a 100644
--- a/android_webview/test/shell/src/draw_fn/context_manager.cc
+++ b/android_webview/test/shell/src/draw_fn/context_manager.cc
@@ -29,13 +29,13 @@
 #include "third_party/skia/include/core/SkDrawable.h"
 #include "third_party/skia/include/core/SkSurface.h"
 #include "third_party/skia/include/core/SkSurfaceProps.h"
-#include "third_party/skia/include/gpu/GrBackendDrawableInfo.h"
 #include "third_party/skia/include/gpu/GrBackendSemaphore.h"
 #include "third_party/skia/include/gpu/GrBackendSurface.h"
 #include "third_party/skia/include/gpu/GrDirectContext.h"
 #include "third_party/skia/include/gpu/GrTypes.h"
 #include "third_party/skia/include/gpu/MutableTextureState.h"
 #include "third_party/skia/include/gpu/ganesh/SkSurfaceGanesh.h"
+#include "third_party/skia/include/gpu/ganesh/vk/GrBackendDrawableInfo.h"
 #include "third_party/skia/include/gpu/ganesh/vk/GrVkBackendSemaphore.h"
 #include "third_party/skia/include/gpu/ganesh/vk/GrVkBackendSurface.h"
 #include "third_party/skia/include/gpu/ganesh/vk/GrVkDirectContext.h"
diff --git a/android_webview/tools/cts_config/webview_cts_hostside_gcs_path.json b/android_webview/tools/cts_config/webview_cts_hostside_gcs_path.json
index c325115..87ba9c6 100644
--- a/android_webview/tools/cts_config/webview_cts_hostside_gcs_path.json
+++ b/android_webview/tools/cts_config/webview_cts_hostside_gcs_path.json
@@ -21,7 +21,11 @@
         "is_hostside": true,
         "excludes": [
           {
-            "match": "com.android.cts.webkit.WebViewHostSideMultipleProfileTest#*",
+            "match": "com.android.cts.webkit.WebViewHostSideMultipleProfileTest#testManagedProfile",
+            "_bug_id": "b/326395159"
+          },
+          {
+            "match": "com.android.cts.webkit.WebViewHostSideMultipleProfileTest#testSecondProfile",
             "_bug_id": "b/326395159"
           }
         ]
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 0041cba7..73c3d5d 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -963,8 +963,12 @@
     "picker/picker_controller.h",
     "picker/picker_copy_media.cc",
     "picker/picker_copy_media.h",
+    "picker/picker_insert_media.cc",
+    "picker/picker_insert_media.h",
     "picker/picker_insert_media_request.cc",
     "picker/picker_insert_media_request.h",
+    "picker/picker_rich_media.cc",
+    "picker/picker_rich_media.h",
     "picker/picker_search_controller.cc",
     "picker/picker_search_controller.h",
     "picker/search/picker_category_search.cc",
@@ -985,6 +989,8 @@
     "picker/views/picker_emoji_item_view.h",
     "picker/views/picker_emoticon_item_view.cc",
     "picker/views/picker_emoticon_item_view.h",
+    "picker/views/picker_focus_indicator.cc",
+    "picker/views/picker_focus_indicator.h",
     "picker/views/picker_gif_view.cc",
     "picker/views/picker_gif_view.h",
     "picker/views/picker_icons.cc",
@@ -997,17 +1003,21 @@
     "picker/views/picker_item_view.h",
     "picker/views/picker_key_event_handler.cc",
     "picker/views/picker_key_event_handler.h",
-    "picker/views/picker_key_event_target.h",
     "picker/views/picker_list_item_container_view.cc",
     "picker/views/picker_list_item_container_view.h",
     "picker/views/picker_list_item_view.cc",
     "picker/views/picker_list_item_view.h",
     "picker/views/picker_page_view.cc",
     "picker/views/picker_page_view.h",
+    "picker/views/picker_positioning.cc",
+    "picker/views/picker_positioning.h",
+    "picker/views/picker_pseudo_focus_handler.h",
     "picker/views/picker_search_field_view.cc",
     "picker/views/picker_search_field_view.h",
     "picker/views/picker_search_results_view.cc",
     "picker/views/picker_search_results_view.h",
+    "picker/views/picker_section_list_view.cc",
+    "picker/views/picker_section_list_view.h",
     "picker/views/picker_section_view.cc",
     "picker/views/picker_section_view.h",
     "picker/views/picker_small_item_grid_view.cc",
@@ -1020,6 +1030,8 @@
     "picker/views/picker_view.cc",
     "picker/views/picker_view.h",
     "picker/views/picker_view_delegate.h",
+    "picker/views/picker_widget.cc",
+    "picker/views/picker_widget.h",
     "picker/views/picker_zero_state_view.cc",
     "picker/views/picker_zero_state_view.h",
     "policy/policy_recommendation_restorer.cc",
@@ -3043,6 +3055,7 @@
     "//chromeos/ash/components/scalable_iph:constants",
     "//chromeos/ash/components/settings",
     "//chromeos/ash/components/standalone_browser",
+    "//chromeos/ash/components/string_matching",
     "//chromeos/ash/components/system",
     "//chromeos/ash/resources:resources_grit",
     "//chromeos/ash/services/assistant/public/cpp",
@@ -3533,6 +3546,7 @@
     "picker/picker_controller_unittest.cc",
     "picker/picker_copy_media_unittest.cc",
     "picker/picker_insert_media_request_unittest.cc",
+    "picker/picker_insert_media_unittest.cc",
     "picker/picker_search_controller_unittest.cc",
     "picker/search/picker_category_search_unittest.cc",
     "picker/search/picker_date_search_unittest.cc",
@@ -3540,14 +3554,18 @@
     "picker/views/picker_contents_view_unittest.cc",
     "picker/views/picker_gif_view_unittest.cc",
     "picker/views/picker_image_item_grid_view_unittest.cc",
+    "picker/views/picker_item_view_unittest.cc",
     "picker/views/picker_key_event_handler_unittest.cc",
     "picker/views/picker_list_item_container_view_unittest.cc",
     "picker/views/picker_list_item_view_unittest.cc",
+    "picker/views/picker_positioning_unittest.cc",
     "picker/views/picker_search_field_view_unittest.cc",
     "picker/views/picker_search_results_view_unittest.cc",
+    "picker/views/picker_section_list_view_unittest.cc",
     "picker/views/picker_section_view_unittest.cc",
     "picker/views/picker_small_item_grid_view_unittest.cc",
     "picker/views/picker_view_unittest.cc",
+    "picker/views/picker_widget_unittest.cc",
     "picker/views/picker_zero_state_view_unittest.cc",
     "policy/policy_recommendation_restorer_unittest.cc",
     "power/hid_battery_util_unittest.cc",
@@ -4721,6 +4739,8 @@
     "wm/gestures/back_gesture/test_back_gesture_contextual_nudge_delegate.h",
     "wm/lock_state_controller_test_api.cc",
     "wm/lock_state_controller_test_api.h",
+    "wm/overview/overview_grid_test_api.cc",
+    "wm/overview/overview_grid_test_api.h",
     "wm/overview/overview_test_util.cc",
     "wm/overview/overview_test_util.h",
     "wm/tablet_mode/tablet_mode_controller_test_api.cc",
diff --git a/ash/DEPS b/ash/DEPS
index 52c3f04..3481a25 100644
--- a/ash/DEPS
+++ b/ash/DEPS
@@ -78,6 +78,7 @@
   "+chromeos/ash/components/peripheral_notification",
   "+chromeos/ash/components/proximity_auth",
   "+chromeos/ash/components/standalone_browser",
+  "+chromeos/ash/components/string_matching",
   "+chromeos/ash/components/system",
   "+chromeos/components/mahi",
   "+chromeos/components/quick_answers",
diff --git a/ash/ambient/metrics/ambient_animation_metrics_recorder.h b/ash/ambient/metrics/ambient_animation_metrics_recorder.h
index 56564972..7d97611 100644
--- a/ash/ambient/metrics/ambient_animation_metrics_recorder.h
+++ b/ash/ambient/metrics/ambient_animation_metrics_recorder.h
@@ -57,7 +57,8 @@
       const lottie::Animation& animation_r) const;
 
   const AmbientUiSettings ui_settings_;
-  base::flat_set<const lottie::Animation*> registered_animations_;
+  base::flat_set<raw_ptr<const lottie::Animation, CtnExperimental>>
+      registered_animations_;
   base::ScopedMultiSourceObservation<lottie::Animation,
                                      lottie::AnimationObserver>
       animation_observations_{this};
diff --git a/ash/ambient/ui/ambient_animation_progress_tracker.cc b/ash/ambient/ui/ambient_animation_progress_tracker.cc
index fa5accb..e92f83a 100644
--- a/ash/ambient/ui/ambient_animation_progress_tracker.cc
+++ b/ash/ambient/ui/ambient_animation_progress_tracker.cc
@@ -9,15 +9,17 @@
 
 #include "base/check.h"
 #include "base/logging.h"
+#include "base/memory/raw_ptr.h"
 #include "base/notreached.h"
 
 namespace ash {
 
 namespace {
 
-void MoveAnimation(base::flat_set<const lottie::Animation*>& from,
-                   base::flat_set<const lottie::Animation*>& to,
-                   const lottie::Animation* animation) {
+void MoveAnimation(
+    base::flat_set<raw_ptr<const lottie::Animation, CtnExperimental>>& from,
+    base::flat_set<raw_ptr<const lottie::Animation, CtnExperimental>>& to,
+    const lottie::Animation* animation) {
   if (to.contains(animation)) {
     CHECK(!from.contains(animation));
     return;
diff --git a/ash/ambient/ui/ambient_animation_progress_tracker.h b/ash/ambient/ui/ambient_animation_progress_tracker.h
index 3a3f8cde..b527f8d 100644
--- a/ash/ambient/ui/ambient_animation_progress_tracker.h
+++ b/ash/ambient/ui/ambient_animation_progress_tracker.h
@@ -9,6 +9,7 @@
 
 #include "ash/ash_export.h"
 #include "base/containers/flat_set.h"
+#include "base/memory/raw_ptr.h"
 #include "base/scoped_multi_source_observation.h"
 #include "ui/lottie/animation.h"
 #include "ui/lottie/animation_observer.h"
@@ -87,9 +88,11 @@
                                      lottie::AnimationObserver>
       animation_observations_{this};
   // Registered animations that have been Start()ed.
-  base::flat_set<const lottie::Animation*> started_animations_;
+  base::flat_set<raw_ptr<const lottie::Animation, CtnExperimental>>
+      started_animations_;
   // Registered animations that have not been Start()ed yet.
-  base::flat_set<const lottie::Animation*> inactive_animations_;
+  base::flat_set<raw_ptr<const lottie::Animation, CtnExperimental>>
+      inactive_animations_;
 };
 
 }  // namespace ash
diff --git a/ash/app_list/app_list_controller_impl.h b/ash/app_list/app_list_controller_impl.h
index 77c4299..9cec34b 100644
--- a/ash/app_list/app_list_controller_impl.h
+++ b/ash/app_list/app_list_controller_impl.h
@@ -41,6 +41,7 @@
 #include "base/time/time.h"
 #include "chromeos/ash/services/assistant/public/cpp/assistant_enums.h"
 #include "ui/aura/window_observer.h"
+#include "ui/compositor/throughput_tracker.h"
 #include "ui/display/display_observer.h"
 #include "ui/display/types/display_constants.h"
 
diff --git a/ash/app_list/app_list_feature_usage_metrics_unittest.cc b/ash/app_list/app_list_feature_usage_metrics_unittest.cc
index 08cc556..fdf32cf 100644
--- a/ash/app_list/app_list_feature_usage_metrics_unittest.cc
+++ b/ash/app_list/app_list_feature_usage_metrics_unittest.cc
@@ -9,6 +9,7 @@
 #include "ash/constants/ash_switches.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
+#include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "base/command_line.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
diff --git a/ash/app_list/app_list_presenter_impl_unittest.cc b/ash/app_list/app_list_presenter_impl_unittest.cc
index e5d0296..13aa697 100644
--- a/ash/app_list/app_list_presenter_impl_unittest.cc
+++ b/ash/app_list/app_list_presenter_impl_unittest.cc
@@ -17,6 +17,7 @@
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
+#include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
 #include "base/test/task_environment.h"
diff --git a/ash/app_list/app_list_util.cc b/ash/app_list/app_list_util.cc
index 41d409c..dee3ae8 100644
--- a/ash/app_list/app_list_util.cc
+++ b/ash/app_list/app_list_util.cc
@@ -161,7 +161,7 @@
 void SetViewIgnoredForAccessibility(views::View* view, bool ignored) {
   auto& view_accessibility = view->GetViewAccessibility();
   view_accessibility.OverrideIsLeaf(ignored);
-  view_accessibility.OverrideIsIgnored(ignored);
+  view_accessibility.SetIsIgnored(ignored);
   view->NotifyAccessibilityEvent(ax::mojom::Event::kTreeChanged, true);
 }
 
diff --git a/ash/app_list/views/app_list_bubble_view_unittest.cc b/ash/app_list/views/app_list_bubble_view_unittest.cc
index 9e2a4e85..aa6d69b 100644
--- a/ash/app_list/views/app_list_bubble_view_unittest.cc
+++ b/ash/app_list/views/app_list_bubble_view_unittest.cc
@@ -1374,33 +1374,33 @@
   LeftClickOn(folder_item);
 
   auto* search_box = GetSearchBoxView();
-  EXPECT_TRUE(search_box->GetViewAccessibility().IsIgnored());
+  EXPECT_TRUE(search_box->GetViewAccessibility().GetIsIgnored());
   EXPECT_TRUE(search_box->GetViewAccessibility().IsLeaf());
   auto* continue_section = GetContinueSectionView();
-  EXPECT_TRUE(continue_section->GetViewAccessibility().IsIgnored());
+  EXPECT_TRUE(continue_section->GetViewAccessibility().GetIsIgnored());
   EXPECT_TRUE(continue_section->GetViewAccessibility().IsLeaf());
   auto* recent_apps = GetRecentAppsView();
-  EXPECT_TRUE(recent_apps->GetViewAccessibility().IsIgnored());
+  EXPECT_TRUE(recent_apps->GetViewAccessibility().GetIsIgnored());
   EXPECT_TRUE(recent_apps->GetViewAccessibility().IsLeaf());
   auto* toast_container = GetToastContainerView();
-  EXPECT_TRUE(toast_container->GetViewAccessibility().IsIgnored());
+  EXPECT_TRUE(toast_container->GetViewAccessibility().GetIsIgnored());
   EXPECT_TRUE(toast_container->GetViewAccessibility().IsLeaf());
   auto* apps_grid = GetAppsGridView();
-  EXPECT_TRUE(apps_grid->GetViewAccessibility().IsIgnored());
+  EXPECT_TRUE(apps_grid->GetViewAccessibility().GetIsIgnored());
   EXPECT_TRUE(apps_grid->GetViewAccessibility().IsLeaf());
 
   // Close the folder.
   PressAndReleaseKey(ui::VKEY_ESCAPE);
 
-  EXPECT_FALSE(search_box->GetViewAccessibility().IsIgnored());
+  EXPECT_FALSE(search_box->GetViewAccessibility().GetIsIgnored());
   EXPECT_FALSE(search_box->GetViewAccessibility().IsLeaf());
-  EXPECT_FALSE(continue_section->GetViewAccessibility().IsIgnored());
+  EXPECT_FALSE(continue_section->GetViewAccessibility().GetIsIgnored());
   EXPECT_FALSE(continue_section->GetViewAccessibility().IsLeaf());
-  EXPECT_FALSE(recent_apps->GetViewAccessibility().IsIgnored());
+  EXPECT_FALSE(recent_apps->GetViewAccessibility().GetIsIgnored());
   EXPECT_FALSE(recent_apps->GetViewAccessibility().IsLeaf());
-  EXPECT_FALSE(toast_container->GetViewAccessibility().IsIgnored());
+  EXPECT_FALSE(toast_container->GetViewAccessibility().GetIsIgnored());
   EXPECT_FALSE(toast_container->GetViewAccessibility().IsLeaf());
-  EXPECT_FALSE(apps_grid->GetViewAccessibility().IsIgnored());
+  EXPECT_FALSE(apps_grid->GetViewAccessibility().GetIsIgnored());
   EXPECT_FALSE(apps_grid->GetViewAccessibility().IsLeaf());
 }
 
diff --git a/ash/app_list/views/apps_container_view_unittest.cc b/ash/app_list/views/apps_container_view_unittest.cc
index a08e89d..39b53aba 100644
--- a/ash/app_list/views/apps_container_view_unittest.cc
+++ b/ash/app_list/views/apps_container_view_unittest.cc
@@ -248,28 +248,28 @@
   // Note: For fullscreen app list, the search box is part of the focus cycle
   // when a folder is open.
   auto* continue_section = helper->GetFullscreenContinueSectionView();
-  EXPECT_TRUE(continue_section->GetViewAccessibility().IsIgnored());
+  EXPECT_TRUE(continue_section->GetViewAccessibility().GetIsIgnored());
   EXPECT_TRUE(continue_section->GetViewAccessibility().IsLeaf());
   auto* recent_apps = helper->GetFullscreenRecentAppsView();
-  EXPECT_TRUE(recent_apps->GetViewAccessibility().IsIgnored());
+  EXPECT_TRUE(recent_apps->GetViewAccessibility().GetIsIgnored());
   EXPECT_TRUE(recent_apps->GetViewAccessibility().IsLeaf());
   auto* toast_container = GetToastContainerView();
-  EXPECT_TRUE(toast_container->GetViewAccessibility().IsIgnored());
+  EXPECT_TRUE(toast_container->GetViewAccessibility().GetIsIgnored());
   EXPECT_TRUE(toast_container->GetViewAccessibility().IsLeaf());
   auto* apps_grid_view = helper->GetRootPagedAppsGridView();
-  EXPECT_TRUE(apps_grid_view->GetViewAccessibility().IsIgnored());
+  EXPECT_TRUE(apps_grid_view->GetViewAccessibility().GetIsIgnored());
   EXPECT_TRUE(apps_grid_view->GetViewAccessibility().IsLeaf());
 
   // Close the folder.
   PressAndReleaseKey(ui::VKEY_ESCAPE);
 
-  EXPECT_FALSE(continue_section->GetViewAccessibility().IsIgnored());
+  EXPECT_FALSE(continue_section->GetViewAccessibility().GetIsIgnored());
   EXPECT_FALSE(continue_section->GetViewAccessibility().IsLeaf());
-  EXPECT_FALSE(recent_apps->GetViewAccessibility().IsIgnored());
+  EXPECT_FALSE(recent_apps->GetViewAccessibility().GetIsIgnored());
   EXPECT_FALSE(recent_apps->GetViewAccessibility().IsLeaf());
-  EXPECT_FALSE(toast_container->GetViewAccessibility().IsIgnored());
+  EXPECT_FALSE(toast_container->GetViewAccessibility().GetIsIgnored());
   EXPECT_FALSE(toast_container->GetViewAccessibility().IsLeaf());
-  EXPECT_FALSE(apps_grid_view->GetViewAccessibility().IsIgnored());
+  EXPECT_FALSE(apps_grid_view->GetViewAccessibility().GetIsIgnored());
   EXPECT_FALSE(apps_grid_view->GetViewAccessibility().IsLeaf());
 }
 
diff --git a/ash/app_list/views/recent_apps_view_unittest.cc b/ash/app_list/views/recent_apps_view_unittest.cc
index c71e410c..45f49d3 100644
--- a/ash/app_list/views/recent_apps_view_unittest.cc
+++ b/ash/app_list/views/recent_apps_view_unittest.cc
@@ -23,6 +23,7 @@
 #include "ash/public/cpp/app_list/app_list_types.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
+#include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "base/strings/stringprintf.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/geometry/point.h"
diff --git a/ash/app_list/views/remove_query_confirmation_dialog.cc b/ash/app_list/views/remove_query_confirmation_dialog.cc
index bf1b183b..b5740a8 100644
--- a/ash/app_list/views/remove_query_confirmation_dialog.cc
+++ b/ash/app_list/views/remove_query_confirmation_dialog.cc
@@ -100,7 +100,7 @@
   title_->layer()->SetFillsBoundsOpaquely(false);
   // Ignore labels for accessibility - the accessible name is defined for the
   // whole dialog view.
-  title_->GetViewAccessibility().OverrideIsIgnored(true);
+  title_->GetViewAccessibility().SetIsIgnored(true);
 
   // Add dialog body.
   body_ =
@@ -125,7 +125,7 @@
   body_->layer()->SetFillsBoundsOpaquely(false);
   // Ignore labels for accessibility - the accessible name is defined for the
   // whole dialog view.
-  body_->GetViewAccessibility().OverrideIsIgnored(true);
+  body_->GetViewAccessibility().SetIsIgnored(true);
 
   auto run_callback = [](RemoveQueryConfirmationDialog* dialog, bool accept) {
     if (!dialog->confirm_callback_)
diff --git a/ash/app_list/views/search_result_image_view.cc b/ash/app_list/views/search_result_image_view.cc
index ec9eed1..8322ff66 100644
--- a/ash/app_list/views/search_result_image_view.cc
+++ b/ash/app_list/views/search_result_image_view.cc
@@ -88,7 +88,7 @@
   SetLayoutManager(std::make_unique<views::FillLayout>());
   result_image_ = AddChildView(std::make_unique<ImagePreviewView>());
   result_image_->SetCanProcessEventsWithinSubtree(false);
-  result_image_->GetViewAccessibility().OverrideIsIgnored(true);
+  result_image_->GetViewAccessibility().SetIsIgnored(true);
 
   views::FocusRing::Install(this);
   views::FocusRing* const focus_ring = views::FocusRing::Get(this);
@@ -138,7 +138,7 @@
   pulsing_block_view_ = AddChildView(std::make_unique<PulsingBlockView>(
       size(), base::Milliseconds(index_ * 200), kRoundedCornerRadius));
   pulsing_block_view_->SetCanProcessEventsWithinSubtree(false);
-  pulsing_block_view_->GetViewAccessibility().OverrideIsIgnored(true);
+  pulsing_block_view_->GetViewAccessibility().SetIsIgnored(true);
 }
 
 gfx::ImageSkia SearchResultImageView::CreateDragImage() {
diff --git a/ash/app_list/views/search_result_view.cc b/ash/app_list/views/search_result_view.cc
index 97c12a5..2d32193 100644
--- a/ash/app_list/views/search_result_view.cc
+++ b/ash/app_list/views/search_result_view.cc
@@ -237,7 +237,7 @@
 views::ImageView* SetupChildImageView(views::FlexLayoutView* parent) {
   views::ImageView* image_view =
       parent->AddChildView(std::make_unique<views::ImageView>());
-  image_view->GetViewAccessibility().OverrideIsIgnored(true);
+  image_view->GetViewAccessibility().SetIsIgnored(true);
   image_view->SetCanProcessEventsWithinSubtree(false);
   image_view->SetVerticalAlignment(views::ImageView::Alignment::kCenter);
   image_view->SetVisible(false);
@@ -259,7 +259,7 @@
   // Ignore labels for accessibility - the result accessible name is defined on
   // the whole result view.
   label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  label->GetViewAccessibility().OverrideIsIgnored(true);
+  label->GetViewAccessibility().SetIsIgnored(true);
   label->SetBackgroundColor(SK_ColorTRANSPARENT);
   label->SetAutoColorReadabilityEnabled(false);
   label->SetEnabledColorId(color_id);
@@ -331,7 +331,7 @@
     std::optional<double> lower_warning_limit) {
   views::ProgressBar* progress_bar_view =
       parent->AddChildView(std::make_unique<views::ProgressBar>());
-  progress_bar_view->GetViewAccessibility().OverrideIsIgnored(true);
+  progress_bar_view->GetViewAccessibility().SetIsIgnored(true);
   progress_bar_view->SetCanProcessEventsWithinSubtree(false);
   progress_bar_view->SetPreferredSize(
       gfx::Size(kProgressBarWidth, kProgressBarHeight));
@@ -363,7 +363,7 @@
       parent->AddChildView(std::make_unique<SearchResultInlineIconView>(
           alterante_icon_and_text_styling));
   inline_icon_view->SetCanProcessEventsWithinSubtree(false);
-  inline_icon_view->GetViewAccessibility().OverrideIsIgnored(true);
+  inline_icon_view->GetViewAccessibility().SetIsIgnored(true);
   inline_icon_view->SetVisible(false);
   inline_icon_view->SetProperty(
       views::kFlexBehaviorKey,
@@ -464,11 +464,11 @@
 
   icon_view_ = AddChildView(std::make_unique<MaskedImageView>());
   icon_view_->SetCanProcessEventsWithinSubtree(false);
-  icon_view_->GetViewAccessibility().OverrideIsIgnored(true);
+  icon_view_->GetViewAccessibility().SetIsIgnored(true);
 
   badge_icon_view_ = AddChildView(std::make_unique<views::ImageView>());
   badge_icon_view_->SetCanProcessEventsWithinSubtree(false);
-  badge_icon_view_->GetViewAccessibility().OverrideIsIgnored(true);
+  badge_icon_view_->GetViewAccessibility().SetIsIgnored(true);
 
   auto* actions_view =
       AddChildView(std::make_unique<SearchResultActionsView>(this));
@@ -596,7 +596,7 @@
       SearchResultTextItem::OverflowBehavior::kNoElide);
   result_text_separator_label_->SetText(
       l10n_util::GetStringUTF16(IDS_ASH_SEARCH_RESULT_SEPARATOR));
-  result_text_separator_label_->GetViewAccessibility().OverrideIsIgnored(true);
+  result_text_separator_label_->GetViewAccessibility().SetIsIgnored(true);
 
   details_container_ = title_and_details_container_->AddChildView(
       std::make_unique<views::FlexLayoutView>());
@@ -620,7 +620,7 @@
       SearchResultTextItem::OverflowBehavior::kNoElide);
   rating_separator_label_->SetText(
       l10n_util::GetStringUTF16(IDS_ASH_SEARCH_RESULT_SEPARATOR));
-  rating_separator_label_->GetViewAccessibility().OverrideIsIgnored(true);
+  rating_separator_label_->GetViewAccessibility().SetIsIgnored(true);
 
   rating_ = SetupChildLabelView(
       title_and_details_container_, view_type_, LabelType::kDetails,
diff --git a/ash/app_list/views/top_icon_animation_view.cc b/ash/app_list/views/top_icon_animation_view.cc
index 177f5e5..03a75a30 100644
--- a/ash/app_list/views/top_icon_animation_view.cc
+++ b/ash/app_list/views/top_icon_animation_view.cc
@@ -231,7 +231,7 @@
 void TopIconAnimationView::OnThemeChanged() {
   views::View::OnThemeChanged();
 
-  if (icon_background_) {
+  if (icon_background_ && icon_background_->layer()) {
     icon_background_->layer()->SetColor(
         GetColorProvider()->GetColor(cros_tokens::kCrosSysSystemOnBaseOpaque));
   }
diff --git a/ash/birch/birch_item.cc b/ash/birch/birch_item.cc
index 6363008..1fab39c 100644
--- a/ash/birch/birch_item.cc
+++ b/ash/birch/birch_item.cc
@@ -95,7 +95,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 BirchFileItem::BirchFileItem(const base::FilePath& file_path,
-                             const std::optional<base::Time>& timestamp)
+                             base::Time timestamp)
     : BirchItem(base::UTF8ToUTF16(file_path.BaseName().value()),
                 ui::ImageModel()),
       file_path(file_path),
@@ -118,13 +118,9 @@
 std::string BirchFileItem::ToString() const {
   std::stringstream ss;
   ss << "File item : {ranking: " << ranking
-     << ", title: " << base::UTF16ToUTF8(title) << ", file_path:" << file_path;
-  if (timestamp.has_value()) {
-    ss << ", timestamp: "
-       << base::UTF16ToUTF8(
-              base::TimeFormatShortDateAndTime(timestamp.value()));
-  }
-  ss << "}";
+     << ", title: " << base::UTF16ToUTF8(title) << ", file_path:" << file_path
+     << ", timestamp: "
+     << base::UTF16ToUTF8(base::TimeFormatShortDateAndTime(timestamp)) << "}";
   return ss.str();
 }
 
diff --git a/ash/birch/birch_item.h b/ash/birch/birch_item.h
index 5d283990..398d7aae 100644
--- a/ash/birch/birch_item.h
+++ b/ash/birch/birch_item.h
@@ -5,7 +5,6 @@
 #ifndef ASH_BIRCH_BIRCH_ITEM_H_
 #define ASH_BIRCH_BIRCH_ITEM_H_
 
-#include <optional>
 #include <string>
 
 #include "ash/ash_export.h"
@@ -82,8 +81,7 @@
 
 // A birch item which contains file path and time information.
 struct ASH_EXPORT BirchFileItem : public BirchItem {
-  BirchFileItem(const base::FilePath& file_path,
-                const std::optional<base::Time>& timestamp);
+  BirchFileItem(const base::FilePath& file_path, base::Time timestamp);
   BirchFileItem(BirchFileItem&&);
   BirchFileItem(const BirchFileItem&);
   BirchFileItem& operator=(const BirchFileItem&);
@@ -91,7 +89,7 @@
   ~BirchFileItem() override;
 
   base::FilePath file_path;
-  std::optional<base::Time> timestamp;
+  base::Time timestamp;
 
   static constexpr char kItemType[] = "FileItem";
 
diff --git a/ash/birch/birch_model.cc b/ash/birch/birch_model.cc
index 61f3a80..e5d431e7 100644
--- a/ash/birch/birch_model.cc
+++ b/ash/birch/birch_model.cc
@@ -115,12 +115,16 @@
 
   BirchRanker ranker(base::Time::Now());
   ranker.RankCalendarItems(&calendar_items_);
+  ranker.RankAttachmentItems(&attachment_items_);
   ranker.RankWeatherItems(&weather_items_);
   // TODO(b/305094126): Rank all data types.
 
   for (auto& event : calendar_items_) {
     all_items.push_back(std::make_unique<BirchCalendarItem>(event));
   }
+  for (auto& event : attachment_items_) {
+    all_items.push_back(std::make_unique<BirchAttachmentItem>(event));
+  }
   for (auto& tab : recent_tab_items_) {
     all_items.push_back(std::make_unique<BirchTabItem>(tab));
   }
diff --git a/ash/birch/birch_model_unittest.cc b/ash/birch/birch_model_unittest.cc
index 42f0772..cff16725 100644
--- a/ash/birch/birch_model_unittest.cc
+++ b/ash/birch/birch_model_unittest.cc
@@ -121,7 +121,7 @@
   EXPECT_THAT(consumer.items_ready_responses(), testing::IsEmpty());
 
   std::vector<BirchFileItem> file_item_list;
-  file_item_list.emplace_back(base::FilePath("test path 1"), std::nullopt);
+  file_item_list.emplace_back(base::FilePath("test path 1"), base::Time());
   model->SetFileSuggestItems(std::move(file_item_list));
   model->SetWeatherItems({});
   model->SetCalendarItems({});
@@ -132,8 +132,8 @@
 
   // Setting the file suggest items should not trigger items ready again, since
   // no data fetch was requested.
-  file_item_list.emplace_back(base::FilePath("test path 1"), std::nullopt);
-  file_item_list.emplace_back(base::FilePath("test path 2"), std::nullopt);
+  file_item_list.emplace_back(base::FilePath("test path 1"), base::Time());
+  file_item_list.emplace_back(base::FilePath("test path 2"), base::Time());
   model->SetFileSuggestItems(std::move(file_item_list));
   EXPECT_THAT(consumer.items_ready_responses(), testing::ElementsAre("0"));
 
@@ -170,7 +170,7 @@
   task_environment()->FastForwardBy(base::Milliseconds(1000));
 
   std::vector<BirchFileItem> file_item_list;
-  file_item_list.emplace_back(base::FilePath("test path 1"), std::nullopt);
+  file_item_list.emplace_back(base::FilePath("test path 1"), base::Time());
   model->SetFileSuggestItems(std::move(file_item_list));
   model->SetRecentTabItems(std::vector<BirchTabItem>());
   std::vector<BirchWeatherItem> weather_items;
@@ -217,7 +217,7 @@
   EXPECT_TRUE(model);
 
   std::vector<BirchFileItem> file_item_list;
-  file_item_list.emplace_back(base::FilePath("test path 1"), std::nullopt);
+  file_item_list.emplace_back(base::FilePath("test path 1"), base::Time());
 
   // Passing time and setting data before requesting a birch data fetch will
   // not notify consumer.
@@ -277,7 +277,7 @@
   EXPECT_THAT(consumer.items_ready_responses(), testing::IsEmpty());
 
   std::vector<BirchFileItem> file_item_list;
-  file_item_list.emplace_back(base::FilePath("test path 1"), std::nullopt);
+  file_item_list.emplace_back(base::FilePath("test path 1"), base::Time());
   model->SetFileSuggestItems(std::move(file_item_list));
   model->SetWeatherItems({});
   model->SetCalendarItems({});
@@ -288,8 +288,8 @@
 
   // Setting the file suggest items should not trigger items ready again, since
   // no data fetch was requested.
-  file_item_list.emplace_back(base::FilePath("test path 1"), std::nullopt);
-  file_item_list.emplace_back(base::FilePath("test path 2"), std::nullopt);
+  file_item_list.emplace_back(base::FilePath("test path 1"), base::Time());
+  file_item_list.emplace_back(base::FilePath("test path 2"), base::Time());
   model->SetFileSuggestItems(std::move(file_item_list));
   EXPECT_THAT(consumer.items_ready_responses(), testing::ElementsAre("0"));
 
@@ -362,7 +362,7 @@
   EXPECT_FALSE(model->IsDataFresh());
 
   std::vector<BirchFileItem> file_item_list;
-  file_item_list.emplace_back(base::FilePath("test path 1"), std::nullopt);
+  file_item_list.emplace_back(base::FilePath("test path 1"), base::Time());
   model->SetFileSuggestItems(std::move(file_item_list));
   std::vector<BirchWeatherItem> weather_item_list;
   weather_item_list.emplace_back(u"cloudy", u"16 c", ui::ImageModel());
@@ -380,7 +380,7 @@
   EXPECT_TRUE(model->IsDataFresh());
 
   EXPECT_THAT(consumer.items_ready_responses(), testing::ElementsAre("0", "1"));
-  EXPECT_EQ(model->GetAllItems().size(), 4u);
+  EXPECT_EQ(model->GetAllItems().size(), 5u);
 
   model->RequestBirchDataFetch(base::BindOnce(&TestModelConsumer::OnItemsReady,
                                               base::Unretained(&consumer),
@@ -402,4 +402,36 @@
   EXPECT_TRUE(model->IsDataFresh());
 }
 
+TEST_F(BirchModelTest, GetAllItems) {
+  BirchModel* model = Shell::Get()->birch_model();
+
+  // Insert one item of each type.
+  std::vector<BirchCalendarItem> calendar_item_list;
+  calendar_item_list.emplace_back(u"Event 1");
+  model->SetCalendarItems(std::move(calendar_item_list));
+  std::vector<BirchAttachmentItem> attachment_item_list;
+  attachment_item_list.emplace_back(u"Attachment 1");
+  model->SetAttachmentItems(std::move(attachment_item_list));
+  std::vector<BirchTabItem> tab_item_list;
+  tab_item_list.emplace_back(u"tab", GURL("foo.bar"), base::Time(),
+                             GURL("favicon"), "session");
+  model->SetRecentTabItems(std::move(tab_item_list));
+  std::vector<BirchFileItem> file_item_list;
+  file_item_list.emplace_back(base::FilePath("test path 1"), base::Time());
+  model->SetFileSuggestItems(std::move(file_item_list));
+  std::vector<BirchWeatherItem> weather_item_list;
+  weather_item_list.emplace_back(u"cloudy", u"16 c", ui::ImageModel());
+  model->SetWeatherItems(std::move(weather_item_list));
+
+  // Verify that GetAllItems() returns the correct number of items and the
+  // code didn't skip a type.
+  std::vector<std::unique_ptr<BirchItem>> all_items = model->GetAllItems();
+  ASSERT_EQ(all_items.size(), 5u);
+  EXPECT_STREQ(all_items[0]->GetItemType(), BirchCalendarItem::kItemType);
+  EXPECT_STREQ(all_items[1]->GetItemType(), BirchAttachmentItem::kItemType);
+  EXPECT_STREQ(all_items[2]->GetItemType(), BirchTabItem::kItemType);
+  EXPECT_STREQ(all_items[3]->GetItemType(), BirchFileItem::kItemType);
+  EXPECT_STREQ(all_items[4]->GetItemType(), BirchWeatherItem::kItemType);
+}
+
 }  // namespace ash
diff --git a/ash/birch/birch_ranker.cc b/ash/birch/birch_ranker.cc
index 7eafc4b..2851630 100644
--- a/ash/birch/birch_ranker.cc
+++ b/ash/birch/birch_ranker.cc
@@ -65,7 +65,32 @@
 }
 
 void BirchRanker::RankAttachmentItems(std::vector<BirchAttachmentItem>* items) {
-  // TODO(b/305094126): Rank all data types.
+  CHECK(items);
+
+  // Sort the attachments by their event start time.
+  std::sort(items->begin(), items->end(),
+            [](const BirchAttachmentItem& a, const BirchAttachmentItem& b) {
+              return a.start_time < b.start_time;
+            });
+
+  const bool is_morning = IsMorning();
+
+  for (BirchAttachmentItem& item : *items) {
+    // Attachments for ongoing events have high priority in the morning and
+    // medium priority the rest of the day.
+    const bool is_ongoing = item.start_time <= now_ && now_ < item.end_time;
+    if (is_ongoing) {
+      item.ranking = is_morning ? 7.f : 10.f;
+      continue;
+    }
+
+    // Attachments for events starting in the next 30 minutes have medium
+    // priority.
+    if (now_ <= item.start_time && item.start_time < now_ + base::Minutes(30)) {
+      item.ranking = 13.f;
+      continue;
+    }
+  }
 }
 
 void BirchRanker::RankFileSuggestItems(std::vector<BirchFileItem>* items) {
diff --git a/ash/birch/birch_ranker_unittest.cc b/ash/birch/birch_ranker_unittest.cc
index 4bce9235..d153ac3 100644
--- a/ash/birch/birch_ranker_unittest.cc
+++ b/ash/birch/birch_ranker_unittest.cc
@@ -148,6 +148,88 @@
   EXPECT_FLOAT_EQ(items[0].ranking, 9.f);
 }
 
+TEST(BirchRankerTest, RankAttachmentItems_Morning) {
+  base::test::ScopedRestoreDefaultTimezone timezone("Etc/GMT");
+
+  // Simulate 9 AM in the morning.
+  base::Time now = TimeFromString("22 Feb 2024 9:00 UTC");
+  BirchRanker ranker(now);
+  ASSERT_TRUE(ranker.IsMorning());
+
+  // Create an attachment for an ongoing event (8 AM to 10 AM).
+  BirchAttachmentItem item0(u"Ongoing");
+  item0.start_time = TimeFromString("22 Feb 2024 08:00 UTC");
+  item0.end_time = TimeFromString("22 Feb 2024 10:00 UTC");
+
+  // Create an attachment for an upcoming event (9:15 to 9:45).
+  BirchAttachmentItem item1(u"Upcoming");
+  item1.start_time = TimeFromString("22 Feb 2024 9:15 UTC");
+  item1.end_time = TimeFromString("22 Feb 2024 9:45 UTC");
+
+  // Create an attachment for another event later in the day (1 PM).
+  BirchAttachmentItem item2(u"Later");
+  item2.start_time = TimeFromString("22 Feb 2024 13:00 UTC");
+  item2.end_time = TimeFromString("22 Feb 2024 13:30 UTC");
+
+  // Put the items in the vector in reverse order to validate that they are
+  // still handled in the correct order (by time) inside the ranker.
+  std::vector<BirchAttachmentItem> items = {item2, item1, item0};
+
+  ranker.RankAttachmentItems(&items);
+
+  ASSERT_EQ(3u, items.size());
+
+  // The ongoing event's item has a high priority.
+  EXPECT_FLOAT_EQ(items[0].ranking, 7.f);
+
+  // The upcoming event's item has a medium priority.
+  EXPECT_FLOAT_EQ(items[1].ranking, 13.f);
+
+  // The later event's item wasn't ranked, so has the default value.
+  EXPECT_FLOAT_EQ(items[2].ranking, std::numeric_limits<float>::max());
+}
+
+TEST(BirchRankerTest, RankAttachmentItems_Evening) {
+  base::test::ScopedRestoreDefaultTimezone timezone("Etc/GMT");
+
+  // Simulate 6 PM in the evening.
+  base::Time now = TimeFromString("22 Feb 2024 18:00 UTC");
+  BirchRanker ranker(now);
+  ASSERT_TRUE(ranker.IsEvening());
+
+  // Create an attachment for an ongoing event (5 PM to 7 PM).
+  BirchAttachmentItem item0(u"Ongoing");
+  item0.start_time = TimeFromString("22 Feb 2024 17:00 UTC");
+  item0.end_time = TimeFromString("22 Feb 2024 19:00 UTC");
+
+  // Create an attachment for an upcoming event (6:15 PM).
+  BirchAttachmentItem item1(u"Upcoming");
+  item1.start_time = TimeFromString("22 Feb 2024 18:15 UTC");
+  item1.end_time = TimeFromString("22 Feb 2024 18:45 UTC");
+
+  // Create an attachment for another event later in the evening (8 PM).
+  BirchAttachmentItem item2(u"Later");
+  item2.start_time = TimeFromString("22 Feb 2024 20:00 UTC");
+  item2.end_time = TimeFromString("22 Feb 2024 20:30 UTC");
+
+  // Put the items in the vector in reverse order to validate that they are
+  // still handled in the correct order (by time) inside the ranker.
+  std::vector<BirchAttachmentItem> items = {item2, item1, item0};
+
+  ranker.RankAttachmentItems(&items);
+
+  ASSERT_EQ(3u, items.size());
+
+  // The ongoing event's item has a medium priority.
+  EXPECT_FLOAT_EQ(items[0].ranking, 10.f);
+
+  // The upcoming event's item has a lower priority.
+  EXPECT_FLOAT_EQ(items[1].ranking, 13.f);
+
+  // The later event's item wasn't ranked, so has the default value.
+  EXPECT_FLOAT_EQ(items[2].ranking, std::numeric_limits<float>::max());
+}
+
 TEST(BirchRankerTest, RankWeatherItems_Morning) {
   base::test::ScopedRestoreDefaultTimezone timezone("Etc/GMT");
 
diff --git a/ash/clipboard/clipboard_history_menu_model_adapter.cc b/ash/clipboard/clipboard_history_menu_model_adapter.cc
index e75f071..dbed6e85 100644
--- a/ash/clipboard/clipboard_history_menu_model_adapter.cc
+++ b/ash/clipboard/clipboard_history_menu_model_adapter.cc
@@ -332,7 +332,7 @@
     for (auto& item_view_command_id_pair :
          menu_model_adapter_->item_views_by_command_id_) {
       views::View* item_view = item_view_command_id_pair.second;
-      item_view->GetViewAccessibility().OverrideIsIgnored(ignore);
+      item_view->GetViewAccessibility().SetIsIgnored(ignore);
     }
   }
 
@@ -530,7 +530,7 @@
       l10n_util::GetStringUTF16(IDS_CLIPBOARD_HISTORY_ITEM_DELETION));
 
   // Enable a11y announcement for the view to be deleted.
-  view_accessibility.OverrideIsIgnored(false);
+  view_accessibility.SetIsIgnored(false);
 
   // Disabling `item_view_to_delete` is more like implementation details.
   // So do not expose it to users.
@@ -721,7 +721,7 @@
 
   // Ignore `container` in accessibility events handling. Let `item_view`
   // handle.
-  container->GetViewAccessibility().OverrideIsIgnored(true);
+  container->GetViewAccessibility().SetIsIgnored(true);
 
   // Margins are managed by `ClipboardHistoryItemView`.
   container->set_vertical_margin(0);
diff --git a/ash/clipboard/views/clipboard_history_main_button.cc b/ash/clipboard/views/clipboard_history_main_button.cc
index 0cb82099..a4ca7e9 100644
--- a/ash/clipboard/views/clipboard_history_main_button.cc
+++ b/ash/clipboard/views/clipboard_history_main_button.cc
@@ -31,7 +31,7 @@
   views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON);
 
   // Let the parent handle accessibility features.
-  GetViewAccessibility().OverrideIsIgnored(/*value=*/true);
+  GetViewAccessibility().SetIsIgnored(true);
 
   // TODO(crbug.com/1205227): Revisit if this comment makes sense still. It was
   // attached to CreateInkDrop() but sounds more about talking about a null
diff --git a/ash/components/arc/arc_features.cc b/ash/components/arc/arc_features.cc
index df9a8e8..e69186f 100644
--- a/ash/components/arc/arc_features.cc
+++ b/ash/components/arc/arc_features.cc
@@ -352,12 +352,12 @@
 // RAM - 1024 MiB.
 BASE_FEATURE(kVmMemorySize,
              "ArcVmMemorySize",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 // Controls the amount to "shift" system RAM when sizing ARCVM. The default
 // value of 0 means that ARCVM's memory will be thr same as the system.
 const base::FeatureParam<int> kVmMemorySizeShiftMiB{&kVmMemorySize, "shift_mib",
-                                                    0};
+                                                    -500};
 
 // Controls the maximum amount of memory to give ARCVM. The default value of
 // INT32_MAX means that ARCVM's memory is not capped.
diff --git a/ash/components/arc/arc_util.cc b/ash/components/arc/arc_util.cc
index a5681f88..bd26cf3e 100644
--- a/ash/components/arc/arc_util.cc
+++ b/ash/components/arc/arc_util.cc
@@ -218,18 +218,6 @@
       ash::switches::kIgnoreArcVmDevConf);
 }
 
-// TODO(b/315507371): Remove after deprecated switches are not in use
-bool IsUreadaheadDisabled() {
-  return base::CommandLine::ForCurrentProcess()->HasSwitch(
-      ash::switches::kArcDisableUreadahead);
-}
-
-// TODO(b/315507371): Remove after deprecated switches are not in use
-bool IsHostUreadaheadGeneration() {
-  return base::CommandLine::ForCurrentProcess()->HasSwitch(
-      ash::switches::kArcHostUreadaheadGeneration);
-}
-
 bool IsArcUseDevCaches() {
   return base::CommandLine::ForCurrentProcess()->HasSwitch(
       ash::switches::kArcUseDevCaches);
diff --git a/ash/components/arc/arc_util.h b/ash/components/arc/arc_util.h
index 2efbfe3..eae6c36 100644
--- a/ash/components/arc/arc_util.h
+++ b/ash/components/arc/arc_util.h
@@ -50,13 +50,14 @@
   JOB_STOP_AND_START,
 };
 
-// Enum for configuring ureadahead mode of operation during ARC boot process.
+// Enum for configuring ureadahead mode of operation during ARC boot process for
+// both host and guest.
 enum class ArcUreadaheadMode {
-  // ARCVM ureadahead is in readahead mode for normal user boot flow.
+  // ARC ureadahead is in readahead mode for normal user boot flow.
   READAHEAD = 0,
-  // ARCVM ureadahead is turned on for generate mode in data collector flow.
+  // ARC ureadahead is turned on for generate mode in data collector flow.
   GENERATE,
-  // ARCVM ureadahead is turned off for disabled mode.
+  // ARC ureadahead is turned off for disabled mode.
   DISABLED,
 };
 
@@ -150,14 +151,6 @@
 // vm_tools/init/arcvm_dev.conf file are ignored during ARCVM start.
 bool IsArcVmDevConfIgnored();
 
-// Returns true if ureadahead is disabled completely, including host and guest
-// parts. See also |GetArcVmUreadaheadMode|.
-bool IsUreadaheadDisabled();
-
-// Returns true in case host ureadahead generation is active in the current
-// session.
-bool IsHostUreadaheadGeneration();
-
 // Returns true if ARC is using dev caches for arccachesetup service.
 bool IsArcUseDevCaches();
 
diff --git a/ash/components/arc/arc_util_unittest.cc b/ash/components/arc/arc_util_unittest.cc
index 3ec9c0a8..827d8e5a 100644
--- a/ash/components/arc/arc_util_unittest.cc
+++ b/ash/components/arc/arc_util_unittest.cc
@@ -310,28 +310,6 @@
   EXPECT_EQ(ArcUreadaheadMode::DISABLED, GetArcUreadaheadMode(mode));
 }
 
-TEST_F(ArcUtilTest, UreadaheadDefault) {
-  EXPECT_FALSE(IsUreadaheadDisabled());
-}
-
-TEST_F(ArcUtilTest, UreadaheadDisabled) {
-  auto* command_line = base::CommandLine::ForCurrentProcess();
-  command_line->InitFromArgv({"", "--arc-disable-ureadahead"});
-  EXPECT_TRUE(IsUreadaheadDisabled());
-}
-
-TEST_F(ArcUtilTest, HostUreadaheadGenerationDefault) {
-  EXPECT_FALSE(IsHostUreadaheadGeneration());
-  EXPECT_FALSE(IsUreadaheadDisabled());
-}
-
-TEST_F(ArcUtilTest, HostUreadaheadGenerationSet) {
-  auto* command_line = base::CommandLine::ForCurrentProcess();
-  command_line->InitFromArgv({"", "--arc-host-ureadahead-generation"});
-  EXPECT_TRUE(IsHostUreadaheadGeneration());
-  EXPECT_FALSE(IsUreadaheadDisabled());
-}
-
 TEST_F(ArcUtilTest, UseDevCachesDefault) {
   EXPECT_FALSE(IsArcUseDevCaches());
 }
diff --git a/ash/components/arc/compat_mode/arc_resize_lock_manager.h b/ash/components/arc/compat_mode/arc_resize_lock_manager.h
index b3b11f8..5578d22 100644
--- a/ash/components/arc/compat_mode/arc_resize_lock_manager.h
+++ b/ash/components/arc/compat_mode/arc_resize_lock_manager.h
@@ -87,7 +87,8 @@
 
   std::unique_ptr<TouchModeMouseRewriter> touch_mode_mouse_rewriter_;
 
-  base::flat_set<aura::Window*> resize_lock_enabled_windows_;
+  base::flat_set<raw_ptr<aura::Window, CtnExperimental>>
+      resize_lock_enabled_windows_;
 
   base::ScopedObservation<aura::Env, aura::EnvObserver> env_observation{this};
 
diff --git a/ash/components/arc/compat_mode/arc_resize_lock_manager_unittest.cc b/ash/components/arc/compat_mode/arc_resize_lock_manager_unittest.cc
index 8cb5760b..e8d65bd 100644
--- a/ash/components/arc/compat_mode/arc_resize_lock_manager_unittest.cc
+++ b/ash/components/arc/compat_mode/arc_resize_lock_manager_unittest.cc
@@ -71,7 +71,8 @@
   }
 
  private:
-  base::flat_set<const aura::Window*> update_compat_mode_button_called;
+  base::flat_set<raw_ptr<const aura::Window, CtnExperimental>>
+      update_compat_mode_button_called;
 };
 
 class TestArcResizeLockManager : public ArcResizeLockManager {
diff --git a/ash/components/arc/compat_mode/overlay_dialog.cc b/ash/components/arc/compat_mode/overlay_dialog.cc
index ece92e9..e5ca555 100644
--- a/ash/components/arc/compat_mode/overlay_dialog.cc
+++ b/ash/components/arc/compat_mode/overlay_dialog.cc
@@ -62,7 +62,7 @@
     return;
 
   auto& view_ax = GetWidget()->GetRootView()->GetViewAccessibility();
-  view_ax.OverrideIsIgnored(true);
+  view_ax.SetIsIgnored(true);
 }
 
 void OverlayDialog::OnThemeChanged() {
diff --git a/ash/components/arc/compat_mode/overlay_dialog_unittest.cc b/ash/components/arc/compat_mode/overlay_dialog_unittest.cc
index b781e28..6f9109bc 100644
--- a/ash/components/arc/compat_mode/overlay_dialog_unittest.cc
+++ b/ash/components/arc/compat_mode/overlay_dialog_unittest.cc
@@ -39,7 +39,7 @@
         std::move(dialog_view)));
 
     const auto& view_ax = widget->GetRootView()->GetViewAccessibility();
-    EXPECT_EQ(!has_dialog_view, view_ax.IsIgnored());
+    EXPECT_EQ(!has_dialog_view, view_ax.GetIsIgnored());
 
     widget->Show();
     EXPECT_FALSE(called);
diff --git a/ash/components/arc/mojom/intent_helper.mojom b/ash/components/arc/mojom/intent_helper.mojom
index e7dd2e3..708f78a 100644
--- a/ash/components/arc/mojom/intent_helper.mojom
+++ b/ash/components/arc/mojom/intent_helper.mojom
@@ -263,6 +263,8 @@
   kGeoLocation,           // Deprecated, replaced with specific scenarios.
   kGeoLocationAtBoot,
   kGeoLocationUserTriggered,
+  // We don't need atBoot for accuracy as the value is in sync with GeoLocation
+  kGeoLocationAccuracyUserTriggered,
 };
 
 // The type of shadow used for Chrome captions.
diff --git a/ash/components/arc/power/arc_power_bridge.cc b/ash/components/arc/power/arc_power_bridge.cc
index 3f7d56bf..e33a620 100644
--- a/ash/components/arc/power/arc_power_bridge.cc
+++ b/ash/components/arc/power/arc_power_bridge.cc
@@ -302,6 +302,12 @@
 
 void ArcPowerBridge::PowerChanged(
     const power_manager::PowerSupplyProperties& proto) {
+  // ARCVM doesn't use this message, since it gets the corresponding
+  // information from crosvm's goldfish battery device.
+  if (arc::IsArcVmEnabled()) {
+    return;
+  }
+
   mojom::PowerInstance* power_instance = ARC_GET_INSTANCE_FOR_METHOD(
       arc_bridge_service_->power(), PowerSupplyInfoChanged);
   if (!power_instance)
diff --git a/ash/components/arc/session/arc_client_adapter.cc b/ash/components/arc/session/arc_client_adapter.cc
index 0c4491d..4066839 100644
--- a/ash/components/arc/session/arc_client_adapter.cc
+++ b/ash/components/arc/session/arc_client_adapter.cc
@@ -92,8 +92,6 @@
   request.set_disable_media_store_maintenance(
       params.disable_media_store_maintenance);
   request.set_disable_download_provider(params.disable_download_provider);
-  request.set_disable_ureadahead(params.disable_ureadahead);
-  request.set_host_ureadahead_generation(params.host_ureadahead_generation);
   request.set_host_ureadahead_mode(
       ToArcMiniInstanceRequestHostUreadaheadMode(params.host_ureadahead_mode));
   request.set_use_dev_caches(params.use_dev_caches);
diff --git a/ash/components/arc/session/arc_container_client_adapter_unittest.cc b/ash/components/arc/session/arc_container_client_adapter_unittest.cc
index 0e67cbf..32a6cab 100644
--- a/ash/components/arc/session/arc_container_client_adapter_unittest.cc
+++ b/ash/components/arc/session/arc_container_client_adapter_unittest.cc
@@ -155,49 +155,6 @@
   EXPECT_TRUE(request.disable_download_provider());
 }
 
-TEST_F(ArcContainerClientAdapterTest, StartArc_UreadaheadByDefault) {
-  StartParams start_params;
-  client_adapter()->StartMiniArc(std::move(start_params),
-                                 base::BindOnce(&OnMiniInstanceStarted));
-  const auto& request = ash::FakeSessionManagerClient::Get()
-                            ->last_start_arc_mini_container_request();
-  EXPECT_TRUE(request.has_disable_ureadahead());
-  EXPECT_FALSE(request.disable_ureadahead());
-}
-
-TEST_F(ArcContainerClientAdapterTest, StartArc_DisableUreadahead) {
-  StartParams start_params;
-  start_params.disable_ureadahead = true;
-  client_adapter()->StartMiniArc(std::move(start_params),
-                                 base::BindOnce(&OnMiniInstanceStarted));
-  const auto& request = ash::FakeSessionManagerClient::Get()
-                            ->last_start_arc_mini_container_request();
-  EXPECT_TRUE(request.has_disable_ureadahead());
-  EXPECT_TRUE(request.disable_ureadahead());
-}
-
-TEST_F(ArcContainerClientAdapterTest,
-       StartArc_NoHostUreadaheadGenerationByDefault) {
-  StartParams start_params;
-  client_adapter()->StartMiniArc(std::move(start_params),
-                                 base::BindOnce(&OnMiniInstanceStarted));
-  const auto& request = ash::FakeSessionManagerClient::Get()
-                            ->last_start_arc_mini_container_request();
-  EXPECT_TRUE(request.has_host_ureadahead_generation());
-  EXPECT_FALSE(request.host_ureadahead_generation());
-}
-
-TEST_F(ArcContainerClientAdapterTest, StartArc_HostUreadaheadGenerationSet) {
-  StartParams start_params;
-  start_params.host_ureadahead_generation = true;
-  client_adapter()->StartMiniArc(std::move(start_params),
-                                 base::BindOnce(&OnMiniInstanceStarted));
-  const auto& request = ash::FakeSessionManagerClient::Get()
-                            ->last_start_arc_mini_container_request();
-  EXPECT_TRUE(request.has_host_ureadahead_generation());
-  EXPECT_TRUE(request.host_ureadahead_generation());
-}
-
 TEST_F(ArcContainerClientAdapterTest, StartArc_DoNotUseDevCachesByDefault) {
   StartParams start_params;
   client_adapter()->StartMiniArc(std::move(start_params),
diff --git a/ash/components/arc/session/arc_session_impl.cc b/ash/components/arc/session/arc_session_impl.cc
index 0caceafa..31ab486 100644
--- a/ash/components/arc/session/arc_session_impl.cc
+++ b/ash/components/arc/session/arc_session_impl.cc
@@ -156,16 +156,6 @@
           ash::switches::kArcDisableDownloadProvider);
 }
 
-void ApplyDisableUreadahed(StartParams* params) {
-  // Host ureadahead generation implies disabling ureadahead.
-  params->disable_ureadahead =
-      IsUreadaheadDisabled() || IsHostUreadaheadGeneration();
-}
-
-void ApplyHostUreadahedGeneration(StartParams* params) {
-  params->host_ureadahead_generation = IsHostUreadaheadGeneration();
-}
-
 void ApplyUseDevCaches(StartParams* params) {
   params->use_dev_caches = IsArcUseDevCaches();
 }
@@ -515,8 +505,6 @@
 
   ApplyDalvikMemoryProfile(system_memory_info_callback_, &params);
   ApplyDisableDownloadProvider(&params);
-  ApplyDisableUreadahed(&params);
-  ApplyHostUreadahedGeneration(&params);
   ApplyUseDevCaches(&params);
   ApplyHostUreadaheadMode(&params);
 
diff --git a/ash/components/arc/session/arc_session_impl_unittest.cc b/ash/components/arc/session/arc_session_impl_unittest.cc
index a9885ce..1850cc8 100644
--- a/ash/components/arc/session/arc_session_impl_unittest.cc
+++ b/ash/components/arc/session/arc_session_impl_unittest.cc
@@ -886,53 +886,6 @@
                   .is_managed_adb_sideloading_allowed);
 }
 
-// Test that validates disabling ureadahead is not enforced by default.
-TEST_F(ArcSessionImplTest, UreadaheadByDefault) {
-  auto arc_session = CreateArcSession();
-  arc_session->StartMiniInstance();
-  base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(
-      GetClient(arc_session.get())->last_start_params().disable_ureadahead);
-}
-
-// Test that validates disabling ureadahead is enforced by switch.
-TEST_F(ArcSessionImplTest, DisableUreadahead) {
-  base::CommandLine* const command_line =
-      base::CommandLine::ForCurrentProcess();
-  command_line->AppendSwitch(ash::switches::kArcDisableUreadahead);
-  auto arc_session = CreateArcSession();
-  arc_session->StartMiniInstance();
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(
-      GetClient(arc_session.get())->last_start_params().disable_ureadahead);
-}
-
-// Test that validates host ureadahead generation flag is not set by default.
-TEST_F(ArcSessionImplTest, NoHostUreadaheadGenerationDefault) {
-  auto arc_session = CreateArcSession();
-  arc_session->StartMiniInstance();
-  base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(GetClient(arc_session.get())
-                   ->last_start_params()
-                   .host_ureadahead_generation);
-}
-
-// Test that validates host ureadahead generation flag is set.
-TEST_F(ArcSessionImplTest, HostUreadaheadGenerationSet) {
-  base::CommandLine* const command_line =
-      base::CommandLine::ForCurrentProcess();
-  command_line->AppendSwitch(ash::switches::kArcHostUreadaheadGeneration);
-  auto arc_session = CreateArcSession();
-  arc_session->StartMiniInstance();
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(GetClient(arc_session.get())
-                  ->last_start_params()
-                  .host_ureadahead_generation);
-  // Host ureadahead generation implies disabling ureadahead.
-  EXPECT_TRUE(
-      GetClient(arc_session.get())->last_start_params().disable_ureadahead);
-}
-
 // Test that validates arc signed in flag is not set by default.
 TEST_F(ArcSessionImplTest, NotArcSignedInByDefault) {
   auto arc_session = CreateArcSession();
diff --git a/ash/components/arc/session/arc_start_params.h b/ash/components/arc/session/arc_start_params.h
index 20e420e..4cf42ee 100644
--- a/ash/components/arc/session/arc_start_params.h
+++ b/ash/components/arc/session/arc_start_params.h
@@ -75,15 +75,6 @@
   // flakiness in tests.
   bool disable_download_provider = false;
 
-  // Flag to disable ureadahead completely, including host and guest parts.
-  // TODO(b/264585671): Refactor this and |host_ureadahead_generation| to
-  // mode enum.
-  bool disable_ureadahead = false;
-
-  // Flag to indicate host ureadahead generation.
-  // TODO(b/264585671): Refactor this and |disable_ureadahead| to mode enum.
-  bool host_ureadahead_generation = false;
-
   // Flag to indicate whether to use dev caches.
   bool use_dev_caches = false;
 
diff --git a/ash/components/arc/session/arc_vm_client_adapter.cc b/ash/components/arc/session/arc_vm_client_adapter.cc
index 89fbbbba..64110ee 100644
--- a/ash/components/arc/session/arc_vm_client_adapter.cc
+++ b/ash/components/arc/session/arc_vm_client_adapter.cc
@@ -837,9 +837,6 @@
     }
 
     std::vector<std::string> environment;
-    if (start_params_.disable_ureadahead) {
-      environment.emplace_back("DISABLE_UREADAHEAD=1");
-    }
     std::deque<JobDesc> jobs{
         // Note: the first Upstart job is a task, and the callback for the start
         // request won't be called until the task finishes. When the callback is
diff --git a/ash/components/arc/session/arc_vm_client_adapter_unittest.cc b/ash/components/arc/session/arc_vm_client_adapter_unittest.cc
index 9aa265d..2f257c3 100644
--- a/ash/components/arc/session/arc_vm_client_adapter_unittest.cc
+++ b/ash/components/arc/session/arc_vm_client_adapter_unittest.cc
@@ -1023,25 +1023,6 @@
   EXPECT_TRUE(ops[1].env.empty());
 }
 
-// Tests that StartMiniArc()'s JOB_STOP_AND_START for
-// |kArcVmPreLoginServicesJobName| has DISABLE_UREADAHEAD variable.
-TEST_F(ArcVmClientAdapterTest, StartMiniArc_DisableUreadahead) {
-  StartParams start_params(GetPopulatedStartParams());
-  start_params.disable_ureadahead = true;
-  ash::FakeUpstartClient::Get()->StartRecordingUpstartOperations();
-  StartMiniArcWithParams(true, std::move(start_params));
-
-  const auto& ops =
-      ash::FakeUpstartClient::Get()->GetRecordedUpstartOperationsForJob(
-          kArcVmPreLoginServicesJobName);
-  ASSERT_EQ(ops.size(), 2u);
-  EXPECT_EQ(ops[0].type, ash::FakeUpstartClient::UpstartOperationType::STOP);
-  EXPECT_EQ(ops[1].type, ash::FakeUpstartClient::UpstartOperationType::START);
-  const auto it_ureadahead =
-      base::ranges::find(ops[1].env, "DISABLE_UREADAHEAD=1");
-  EXPECT_NE(ops[1].env.end(), it_ureadahead);
-}
-
 // Tests that StartMiniArc() handles arcvm-post-vm-start-services stop failures
 // properly.
 TEST_F(ArcVmClientAdapterTest,
@@ -2189,7 +2170,8 @@
   StartParams start_params(GetPopulatedStartParams());
   StartMiniArcWithParams(true, std::move(start_params));
   const auto& request = GetTestConciergeClient()->start_arc_vm_request();
-  EXPECT_EQ(request.memory_mib(), total_mib / 4);
+  // shift_mib is -500 by default
+  EXPECT_EQ(request.memory_mib(), total_mib / 4 - 500);
 }
 
 // Test that ARCMVM size is set by both ram_percentage and shift_mib.
@@ -2501,8 +2483,9 @@
   StartMiniArcWithParams(true, std::move(start_params));
 
   const auto& request = GetTestConciergeClient()->start_arc_vm_request();
-  // 5GB system should result in 4GB VM size => 2GB ZRAM.
-  EXPECT_EQ(2048u, request.guest_zram_mib());
+  // As shift_mib for memory size is -500 by default,
+  // 5GB system should result in 4.5GB VM size => 2.25GB ZRAM.
+  EXPECT_EQ(2310u, request.guest_zram_mib());
 }
 
 TEST_F(ArcVmClientAdapterTest, ArcGuestZramSizeByPercentage_4GbSystem) {
@@ -2525,8 +2508,9 @@
   StartMiniArcWithParams(true, std::move(start_params));
 
   const auto& request = GetTestConciergeClient()->start_arc_vm_request();
-  // 4GB system should result in 3GB VM size => 1.5GB ZRAM.
-  EXPECT_EQ(1536u, request.guest_zram_mib());
+  // As shift_mib for memory size is -500 by default,
+  // 4GB system should result in 3.5GB VM size => 1.75GB ZRAM.
+  EXPECT_EQ(1798u, request.guest_zram_mib());
 }
 
 TEST_F(ArcVmClientAdapterTest, ArcGuestZramSizeByPercentage_CustomMem) {
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 9322bc9..7b4fd69 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -1171,6 +1171,11 @@
              "FilesLocalImageSearch",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Enables materialized views in Files App.
+BASE_FEATURE(kFilesMaterializedViews,
+             "FilesMaterializedViews",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // Enables partitioning of removable disks in file manager.
 BASE_FEATURE(kFilesSinglePartitionFormat,
              "FilesSinglePartitionFormat",
@@ -1202,9 +1207,7 @@
              base::FEATURE_DISABLED_BY_DEFAULT);
 
 // Enables chrome.fileSystemProvider file systems in Files app Recents view.
-BASE_FEATURE(kFSPsInRecents,
-             "FSPsInRecents",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+BASE_FEATURE(kFSPsInRecents, "FSPsInRecents", base::FEATURE_ENABLED_BY_DEFAULT);
 
 // Maximum delay to wait for restoring Floating Workspace after login.
 constexpr base::FeatureParam<base::TimeDelta>
@@ -2780,6 +2783,13 @@
              "UseAuthPanelInPasswordManager",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// This features toggles which implementation is used for authentication UIs on
+// ChromeOS settings. When the feature is enabled,
+// `AuthPanel` is used as an authentication UI.
+BASE_FEATURE(kUseAuthPanelInSettings,
+             "UseAuthPanelInSettings",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // Use the staging URL as part of the "Messages" feature under "Connected
 // Devices" settings.
 BASE_FEATURE(kUseMessagesStagingUrl,
@@ -4517,4 +4527,8 @@
   return base::FeatureList::IsEnabled(kUseAuthPanelInPasswordManager);
 }
 
+bool IsUseAuthPanelInSettingsEnabled() {
+  return base::FeatureList::IsEnabled(kUseAuthPanelInSettings);
+}
+
 }  // namespace ash::features
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index fb94d1e..f629f00 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -354,6 +354,7 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kFilesAppExperimental);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kFilesConflictDialog);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kFilesLocalImageSearch);
+COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kFilesMaterializedViews);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kFilesNewDirectoryTree);
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kFilesSinglePartitionFormat);
@@ -844,6 +845,8 @@
 BASE_DECLARE_FEATURE(kUseAndroidStagingSmds);
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kUseAuthPanelInPasswordManager);
+COMPONENT_EXPORT(ASH_CONSTANTS)
+BASE_DECLARE_FEATURE(kUseAuthPanelInSettings);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kUseLoginShelfWidget);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kUseMessagesStagingUrl);
 COMPONENT_EXPORT(ASH_CONSTANTS)
@@ -1279,6 +1282,7 @@
 COMPONENT_EXPORT(ASH_CONSTANTS)
 bool IsUnmanagedDeviceDeviceTrustConnectorFeatureEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsUseAuthPanelInPasswordManagerEnabled();
+COMPONENT_EXPORT(ASH_CONSTANTS) bool IsUseAuthPanelInSettingsEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsUserEducationEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsUpstreamTrustedReportsFirmwareEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsVideoConferenceEnabled();
diff --git a/ash/constants/ash_switches.cc b/ash/constants/ash_switches.cc
index 68b0c549..add63503 100644
--- a/ash/constants/ash_switches.cc
+++ b/ash/constants/ash_switches.cc
@@ -123,18 +123,6 @@
 // Used in autotest to disable TTS cache which is on by default.
 const char kArcDisableTtsCache[] = "arc-disable-tts-cache";
 
-// Flag that disables ureadahead completely, including host and guest parts.
-// To enable only guest ureadahead, please use --arcvm-ureadahead-mode=readahead
-// in combination with this switch (see |kArcVmUreadaheadMode|).
-// TODO(b/264585671): Refactore this and |kArcHostUreadaheadGeneration| to
-// mode enum.
-const char kArcDisableUreadahead[] = "arc-disable-ureadahead";
-
-// Flag that indicates host ureadahead generation session. Note, it is still
-// valid even in case of kArcDisableUreadahead is set.
-// TODO(b/264585671): Refactor this and |kArcDisableUreadahead| to mode enum.
-const char kArcHostUreadaheadGeneration[] = "arc-host-ureadahead-generation";
-
 // Flag that indicates ARC is using dev caches generated by data collector in
 // Uprev rather than caches from CrOS build stage for arccachesetup service.
 const char kArcUseDevCaches[] = "arc-use-dev-caches";
diff --git a/ash/constants/ash_switches.h b/ash/constants/ash_switches.h
index 889697e..27e908d 100644
--- a/ash/constants/ash_switches.h
+++ b/ash/constants/ash_switches.h
@@ -44,9 +44,6 @@
 extern const char kArcDisableMediaStoreMaintenance[];
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kArcDisablePlayAutoInstall[];
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kArcDisableTtsCache[];
-COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kArcDisableUreadahead[];
-COMPONENT_EXPORT(ASH_CONSTANTS)
-extern const char kArcHostUreadaheadGeneration[];
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kArcUseDevCaches[];
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kArcErofs[];
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kArcForcePostBootDexOpt[];
diff --git a/ash/display/display_configuration_controller.cc b/ash/display/display_configuration_controller.cc
index c285f56..6d4ade1 100644
--- a/ash/display/display_configuration_controller.cc
+++ b/ash/display/display_configuration_controller.cc
@@ -164,8 +164,13 @@
 
 display::Display::Rotation DisplayConfigurationController::GetTargetRotation(
     int64_t display_id) {
-  if (!display_manager_->IsDisplayIdValid(display_id))
+  // The display for `display_id` may exist but there may be no root window for
+  // it, such as in the case of Unified Display. Query for the target rotation
+  // only if the root window exists.
+  if (!display_manager_->IsDisplayIdValid(display_id) ||
+      !Shell::GetRootWindowForDisplayId(display_id)) {
     return display::Display::ROTATE_0;
+  }
 
   ScreenRotationAnimator* animator =
       GetScreenRotationAnimatorForDisplay(display_id);
diff --git a/ash/display/screen_orientation_controller.cc b/ash/display/screen_orientation_controller.cc
index 2813826..8c71d95f 100644
--- a/ash/display/screen_orientation_controller.cc
+++ b/ash/display/screen_orientation_controller.cc
@@ -10,6 +10,7 @@
 #include "ash/constants/ash_switches.h"
 #include "ash/shell.h"
 #include "ash/wm/mru_window_tracker.h"
+#include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_state_observer.h"
 #include "ash/wm/window_util.h"
@@ -25,6 +26,7 @@
 #include "ui/display/screen.h"
 #include "ui/display/util/display_util.h"
 #include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/vector3d_f.h"
 #include "ui/wm/public/activation_client.h"
 
 namespace ash {
diff --git a/ash/events/event_rewriter_controller_impl.cc b/ash/events/event_rewriter_controller_impl.cc
index c33b7cd2..441ae54 100644
--- a/ash/events/event_rewriter_controller_impl.cc
+++ b/ash/events/event_rewriter_controller_impl.cc
@@ -127,8 +127,6 @@
     AddEventRewriter(std::move(peripheral_customization_event_rewriter));
   }
   AddEventRewriter(std::move(prerewritten_event_forwarder));
-  AddEventRewriter(std::move(accessibility_event_rewriter));
-  AddEventRewriter(std::move(keyboard_driven_event_rewriter));
   AddEventRewriter(std::move(keyboard_device_id_event_rewriter));
   if (features::IsKeyboardRewriterFixEnabled()) {
     auto keyboard_modifier_event_rewriter =
@@ -139,6 +137,13 @@
             ash::input_method::InputMethodManager::Get()->GetImeKeyboard());
     AddEventRewriter(std::move(keyboard_modifier_event_rewriter));
   }
+  // Accessibility rewriter is applied between modifier event rewriters and
+  // EventRewriterAsh. Specifically, Search modifier is captured by the
+  // accessibility rewriter, that should be the ones after modifier remapping.
+  // However, accessibility rewriter wants to capture it before it is rewritten
+  // into 6-pack keys, which is done in EventRewriterAsh.
+  AddEventRewriter(std::move(accessibility_event_rewriter));
+  AddEventRewriter(std::move(keyboard_driven_event_rewriter));
   AddEventRewriter(std::move(event_rewriter_ash));
 }
 
diff --git a/ash/frame/caption_buttons/frame_size_button_unittest.cc b/ash/frame/caption_buttons/frame_size_button_unittest.cc
index 36259d35..fb19260 100644
--- a/ash/frame/caption_buttons/frame_size_button_unittest.cc
+++ b/ash/frame/caption_buttons/frame_size_button_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "ash/display/screen_orientation_controller.h"
 #include "ash/display/screen_orientation_controller_test_api.h"
+#include "ash/public/cpp/tablet_mode.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/ash_test_util.h"
diff --git a/ash/glanceables/tasks/glanceables_task_view.cc b/ash/glanceables/tasks/glanceables_task_view.cc
index f4f71ef..ef3f471 100644
--- a/ash/glanceables/tasks/glanceables_task_view.cc
+++ b/ash/glanceables/tasks/glanceables_task_view.cc
@@ -59,7 +59,7 @@
   label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
   // Views should not be individually selected for accessibility. Accessible
   // name and behavior comes from the parent.
-  label->GetViewAccessibility().OverrideIsIgnored(true);
+  label->GetViewAccessibility().SetIsIgnored(true);
   label->SetBackgroundColor(SK_ColorTRANSPARENT);
   label->SetAutoColorReadabilityEnabled(false);
   return label;
diff --git a/ash/glanceables/tasks/glanceables_task_view_v2.cc b/ash/glanceables/tasks/glanceables_task_view_v2.cc
index c6fd45b0..f41e0ef 100644
--- a/ash/glanceables/tasks/glanceables_task_view_v2.cc
+++ b/ash/glanceables/tasks/glanceables_task_view_v2.cc
@@ -23,8 +23,10 @@
 #include "ash/system/time/calendar_utils.h"
 #include "ash/system/time/date_helper.h"
 #include "base/functional/bind.h"
+#include "base/location.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/task/sequenced_task_runner.h"
 #include "base/types/cxx23_to_underlying.h"
 #include "chromeos/ash/components/network/network_handler.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
@@ -42,6 +44,7 @@
 #include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/background.h"
 #include "ui/views/controls/button/button.h"
+#include "ui/views/controls/button/button_controller.h"
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/focus_ring.h"
@@ -51,7 +54,6 @@
 #include "ui/views/controls/textfield/textfield_controller.h"
 #include "ui/views/layout/flex_layout_view.h"
 #include "ui/views/widget/widget_delegate.h"
-#include "ui/wm/core/focus_controller.h"
 
 namespace ash {
 namespace {
@@ -85,7 +87,7 @@
   label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
   // Views should not be individually selected for accessibility. Accessible
   // name and behavior comes from the parent.
-  label->GetViewAccessibility().OverrideIsIgnored(true);
+  label->GetViewAccessibility().SetIsIgnored(true);
   label->SetBackgroundColor(SK_ColorTRANSPARENT);
   label->SetAutoColorReadabilityEnabled(false);
   return label;
@@ -138,7 +140,7 @@
 
  public:
   using OnFinishedEditingCallback =
-      base::OnceCallback<void(const std::u16string& title)>;
+      base::RepeatingCallback<void(const std::u16string& title)>;
 
   TaskViewTextField(const std::u16string& title,
                     OnFinishedEditingCallback on_finished_editing)
@@ -192,8 +194,7 @@
     // Entering inactive state from the active state implies the editing is
     // done.
     if (!IsActive()) {
-      // Running `on_finished_editing_` deletes `this`.
-      std::move(on_finished_editing_).Run(GetText());
+      on_finished_editing_.Run(GetText());
     }
   }
 
@@ -216,6 +217,8 @@
     SetEnabledTextColorIds(cros_tokens::kCrosSysPrimary);
     label()->SetFontList(TypographyProvider::Get()->ResolveTypographyToken(
         TypographyToken::kCrosButton2));
+    button_controller()->set_notify_action(
+        views::ButtonController::NotifyAction::kOnPress);
   }
 };
 
@@ -409,6 +412,32 @@
 
 GlanceablesTaskViewV2::~GlanceablesTaskViewV2() = default;
 
+void GlanceablesTaskViewV2::OnViewBlurred(views::View* observed_view) {
+  if ((observed_view == edit_in_browser_button_ ||
+       observed_view == task_title_textfield_) &&
+      (!edit_in_browser_button_ || !edit_in_browser_button_->HasFocus()) &&
+      (!task_title_textfield_ || !task_title_textfield_->HasFocus())) {
+    edit_exit_observer_.RemoveAllObservations();
+    // Schedule a task to update task view state to kView. Done asynchronously
+    // to let the focus change to complete. State update will remove the blurred
+    // view while focus is still changing, which may cause a crash -
+    // b/324409607.
+    base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
+        FROM_HERE,
+        base::BindOnce(&GlanceablesTaskViewV2::UpdateTaskTitleViewForState,
+                       state_change_weak_ptr_factory_.GetWeakPtr(),
+                       TaskTitleViewState::kView));
+  }
+}
+
+void GlanceablesTaskViewV2::OnViewIsDeleting(views::View* observed_view) {
+  edit_exit_observer_.RemoveObservation(observed_view);
+
+  if (!edit_exit_observer_.IsObservingAnySource()) {
+    UpdateTaskTitleViewForState(TaskTitleViewState::kView);
+  }
+}
+
 const views::ImageButton* GlanceablesTaskViewV2::GetCheckButtonForTest() const {
   return check_button_;
 }
@@ -419,6 +448,9 @@
 
 void GlanceablesTaskViewV2::UpdateTaskTitleViewForState(
     TaskTitleViewState state) {
+  state_change_weak_ptr_factory_.InvalidateWeakPtrs();
+  edit_exit_observer_.RemoveAllObservations();
+
   task_title_button_ = nullptr;
   task_title_textfield_ = nullptr;
   tasks_title_view_->RemoveAllChildViews();
@@ -436,6 +468,7 @@
               task_title_, base::BindRepeating(
                                &GlanceablesTaskViewV2::TaskTitleButtonPressed,
                                base::Unretained(this))));
+      task_title_button_->SetEnabled(!saving_task_changes_);
       task_title_button_->UpdateLabelForState(
           /*completed=*/check_button_->checked());
       break;
@@ -443,14 +476,15 @@
       task_title_textfield_ =
           tasks_title_view_->AddChildView(std::make_unique<TaskViewTextField>(
               task_title_,
-              base::BindOnce(&GlanceablesTaskViewV2::OnFinishedEditing,
-                             base::Unretained(this))));
+              base::BindRepeating(&GlanceablesTaskViewV2::OnFinishedEditing,
+                                  base::Unretained(this))));
       GetWidget()->widget_delegate()->SetCanActivate(true);
       task_title_textfield_->RequestFocus();
 
       edit_in_browser_button_ = contents_view_->AddChildView(
           std::make_unique<EditInBrowserButton>(edit_in_browser_callback_));
-      check_button_->SetEnabled(false);
+      edit_exit_observer_.AddObservation(task_title_textfield_);
+      edit_exit_observer_.AddObservation(edit_in_browser_button_);
       break;
   }
 
@@ -491,6 +525,10 @@
     return;
   }
 
+  if (saving_task_changes_) {
+    return;
+  }
+
   bool target_state = !check_button_->checked();
   check_button_->SetChecked(target_state);
 
@@ -518,18 +556,18 @@
     task_title_ = title;
   }
 
-  // Skip the title view resetting when the window lost active. Let the view
-  // hierarchy clean up be done by the native widget.
-  if (!(GetWidget() &&
-        GetWidget()->GetNativeWindow() !=
-            Shell::Get()->focus_controller()->GetActiveWindow())) {
-    UpdateTaskTitleViewForState(TaskTitleViewState::kView);
+  if (task_title_textfield_ && task_title_textfield_->HasFocus()) {
+    GetFocusManager()->ClearFocus();
   }
 
   if (task_id_.empty() || task_title_ != old_title) {
+    saving_task_changes_ = true;
     if (task_title_button_) {
       task_title_button_->SetEnabled(false);
     }
+    if (task_title_textfield_) {
+      task_title_textfield_->SetEnabled(false);
+    }
     // Note: result for task addition flow will be recorded in the parent view,
     // which initialized add task flow.
     if (!task_id_.empty()) {
@@ -545,7 +583,6 @@
   } else {
     // Note: result for task addition flow will be recorded in the parent view,
     // which initialized add task flow.
-    check_button_->SetEnabled(true);
     if (!task_id_.empty()) {
       RecordTaskModificationResult(TaskModificationResult::kCancelled);
     }
@@ -553,10 +590,13 @@
 }
 
 void GlanceablesTaskViewV2::OnSaved(const api::Task* task) {
-  check_button_->SetEnabled(true);
+  saving_task_changes_ = false;
   if (task_title_button_) {
     task_title_button_->SetEnabled(true);
   }
+  if (task_title_textfield_) {
+    task_title_textfield_->SetEnabled(true);
+  }
   if (task) {
     task_id_ = task->id;
   }
diff --git a/ash/glanceables/tasks/glanceables_task_view_v2.h b/ash/glanceables/tasks/glanceables_task_view_v2.h
index fbd6ad6..460da8b 100644
--- a/ash/glanceables/tasks/glanceables_task_view_v2.h
+++ b/ash/glanceables/tasks/glanceables_task_view_v2.h
@@ -13,8 +13,10 @@
 #include "base/functional/callback_forward.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/scoped_multi_source_observation.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/views/layout/flex_layout_view.h"
+#include "ui/views/view_observer.h"
 
 namespace views {
 class ImageButton;
@@ -44,7 +46,8 @@
 // | |                 | | +-----------------------------------+ | |
 // | +-----------------+ +---------------------------------------+ |
 // +---------------------------------------------------------------+
-class ASH_EXPORT GlanceablesTaskViewV2 : public views::FlexLayoutView {
+class ASH_EXPORT GlanceablesTaskViewV2 : public views::FlexLayoutView,
+                                         public views::ViewObserver {
   METADATA_HEADER(GlanceablesTaskViewV2, views::FlexLayoutView)
 
  public:
@@ -70,6 +73,10 @@
   GlanceablesTaskViewV2& operator=(const GlanceablesTaskViewV2&) = delete;
   ~GlanceablesTaskViewV2() override;
 
+  // views::ViewObserver:
+  void OnViewBlurred(views::View* observed_view) override;
+  void OnViewIsDeleting(views::View* observed_view) override;
+
   const views::ImageButton* GetCheckButtonForTest() const;
   bool GetCompletedForTest() const;
 
@@ -115,6 +122,8 @@
   // Title of the task.
   std::u16string task_title_;
 
+  bool saving_task_changes_ = false;
+
   // Marks the task as completed.
   const MarkAsCompletedCallback mark_as_completed_callback_;
 
@@ -127,6 +136,12 @@
   // Shows an error message in the parent `GlanceablesTasksView`.
   const ShowErrorMessageCallback show_error_message_callback_;
 
+  base::ScopedMultiSourceObservation<views::View, GlanceablesTaskViewV2>
+      edit_exit_observer_{this};
+
+  base::WeakPtrFactory<GlanceablesTaskViewV2> state_change_weak_ptr_factory_{
+      this};
+
   base::WeakPtrFactory<GlanceablesTaskViewV2> weak_ptr_factory_{this};
 };
 
diff --git a/ash/glanceables/tasks/glanceables_task_view_v2_unittest.cc b/ash/glanceables/tasks/glanceables_task_view_v2_unittest.cc
index ed23856d..326e011 100644
--- a/ash/glanceables/tasks/glanceables_task_view_v2_unittest.cc
+++ b/ash/glanceables/tasks/glanceables_task_view_v2_unittest.cc
@@ -274,6 +274,7 @@
     PressAndReleaseKey(ui::VKEY_D);
 
     PressAndReleaseKey(ui::VKEY_ESCAPE);
+    base::RunLoop().RunUntilIdle();
   }
 
   {
@@ -346,12 +347,97 @@
   PressAndReleaseKey(ui::VKEY_P);
   PressAndReleaseKey(ui::VKEY_D);
   PressAndReleaseKey(ui::VKEY_ESCAPE);
+  base::RunLoop().RunUntilIdle();
 
   const auto [task_view, task_id, title, callback] = future.Take();
   EXPECT_EQ(task_id, "task-id");
   EXPECT_EQ(title, "Task title upd");
 }
 
+TEST_F(GlanceablesTaskViewStableLaunchTest, CommitEditedTaskOnTab) {
+  const auto task = api::Task("task-id", "Task title",
+                              /*due=*/std::nullopt, /*completed=*/false,
+                              /*has_subtasks=*/false, /*has_email_link=*/false,
+                              /*has_notes=*/false, /*updated=*/base::Time());
+
+  base::test::TestFuture<base::WeakPtr<GlanceablesTaskViewV2>,
+                         const std::string&, const std::string&,
+                         api::TasksClient::OnTaskSavedCallback>
+      future;
+
+  const auto widget = CreateFramelessTestWidget();
+  widget->SetFullscreen(true);
+  auto* const view =
+      widget->SetContentsView(std::make_unique<GlanceablesTaskViewV2>(
+          &task, /*mark_as_completed_callback=*/base::DoNothing(),
+          /*save_callback=*/future.GetRepeatingCallback(),
+          /*edit_in_browser_callback=*/base::DoNothing(),
+          /*show_error_message_callback=*/base::DoNothing()));
+  ASSERT_TRUE(view);
+
+  view->UpdateTaskTitleViewForState(
+      GlanceablesTaskViewV2::TaskTitleViewState::kEdit);
+  PressAndReleaseKey(ui::VKEY_SPACE);
+  PressAndReleaseKey(ui::VKEY_U);
+  PressAndReleaseKey(ui::VKEY_P);
+  PressAndReleaseKey(ui::VKEY_D);
+
+  PressAndReleaseKey(ui::VKEY_TAB);
+  base::RunLoop().RunUntilIdle();
+
+  {
+    auto [task_view, task_id, title, callback] = future.Take();
+    EXPECT_EQ(task_id, "task-id");
+    EXPECT_EQ(title, "Task title upd");
+    const auto updated_task =
+        api::Task("task-id", "New upd",
+                  /*due=*/std::nullopt, /*completed=*/false,
+                  /*has_subtasks=*/false,
+                  /*has_email_link=*/false, /*has_notes=*/false,
+                  /*updated=*/base::Time::Now());
+    std::move(callback).Run(&updated_task);
+  }
+
+  EXPECT_FALSE(views::AsViewClass<views::Label>(view->GetViewByID(
+      base::to_underlying(GlanceablesViewId::kTaskItemTitleLabel))));
+  EXPECT_TRUE(views::AsViewClass<views::Textfield>(view->GetViewByID(
+      base::to_underlying(GlanceablesViewId::kTaskItemTitleTextField))));
+  const auto* edit_in_browser_button = view->GetViewByID(
+      base::to_underlying(GlanceablesViewId::kTaskItemEditInBrowserLabel));
+  ASSERT_TRUE(edit_in_browser_button);
+  EXPECT_TRUE(edit_in_browser_button->HasFocus());
+
+  PressAndReleaseKey(ui::VKEY_TAB, ui::EF_SHIFT_DOWN);
+  base::RunLoop().RunUntilIdle();
+
+  PressAndReleaseKey(ui::VKEY_RIGHT);
+  PressAndReleaseKey(ui::VKEY_A);
+
+  PressAndReleaseKey(ui::VKEY_TAB);
+  base::RunLoop().RunUntilIdle();
+
+  {
+    const auto [task_view, task_id, title, callback] = future.Take();
+    EXPECT_EQ(task_id, "task-id");
+    EXPECT_EQ(title, "Task title upda");
+  }
+
+  edit_in_browser_button = view->GetViewByID(
+      base::to_underlying(GlanceablesViewId::kTaskItemEditInBrowserLabel));
+  ASSERT_TRUE(edit_in_browser_button);
+  EXPECT_TRUE(edit_in_browser_button->HasFocus());
+
+  view->GetFocusManager()->ClearFocus();
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(views::AsViewClass<views::Label>(view->GetViewByID(
+      base::to_underlying(GlanceablesViewId::kTaskItemTitleLabel))));
+  EXPECT_FALSE(views::AsViewClass<views::Textfield>(view->GetViewByID(
+      base::to_underlying(GlanceablesViewId::kTaskItemTitleTextField))));
+  EXPECT_FALSE(views::AsViewClass<views::Textfield>(view->GetViewByID(
+      base::to_underlying(GlanceablesViewId::kTaskItemEditInBrowserLabel))));
+}
+
 TEST_F(GlanceablesTaskViewStableLaunchTest, SupportsEditingRightAfterAdding) {
   base::test::TestFuture<base::WeakPtr<GlanceablesTaskViewV2>,
                          const std::string&, const std::string&,
@@ -424,7 +510,6 @@
 
   view->UpdateTaskTitleViewForState(
       GlanceablesTaskViewV2::TaskTitleViewState::kEdit);
-  EXPECT_FALSE(view->GetCheckButtonForTest()->GetEnabled());
   EXPECT_FALSE(view->GetCompletedForTest());
 
   PressAndReleaseKey(ui::VKEY_N, ui::EF_SHIFT_DOWN);
@@ -437,7 +522,9 @@
   auto [task_view, task_id, title, callback] = future.Take();
   EXPECT_TRUE(task_id.empty());
   EXPECT_EQ(title, "New");
-  EXPECT_FALSE(view->GetCheckButtonForTest()->GetEnabled());
+  EXPECT_FALSE(view->GetCompletedForTest());
+  base::RunLoop().RunUntilIdle();
+
   EXPECT_FALSE(view->GetCompletedForTest());
 
   const auto* const title_label =
diff --git a/ash/glanceables/tasks/glanceables_tasks_view.cc b/ash/glanceables/tasks/glanceables_tasks_view.cc
index c3ac36a..722b44fd 100644
--- a/ash/glanceables/tasks/glanceables_tasks_view.cc
+++ b/ash/glanceables/tasks/glanceables_tasks_view.cc
@@ -29,7 +29,9 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/i18n/time_formatting.h"
+#include "base/location.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/task/sequenced_task_runner.h"
 #include "base/time/time.h"
 #include "base/types/cxx23_to_underlying.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -52,7 +54,6 @@
 #include "ui/views/layout/flex_layout_view.h"
 #include "ui/views/view.h"
 #include "ui/views/view_class_properties.h"
-#include "ui/wm/core/focus_controller.h"
 #include "url/gurl.h"
 
 namespace ash {
@@ -467,21 +468,19 @@
     const std::string& title,
     api::TasksClient::OnTaskSavedCallback callback) {
   if (task_id.empty()) {
-    // Manually deleting `view` may cause the focus manager try storing the
-    // dangling `view`'s descendants. Let native window handle the view deletion
-    // when it lost active.
-    if (GetWidget() &&
-        GetWidget()->GetNativeWindow() !=
-            Shell::Get()->focus_controller()->GetActiveWindow()) {
-      return;
-    }
-
     // Empty `task_id` means that the task has not yet been created. Verify that
     // this task has a non-empty title, otherwise just delete the `view` from
     // the scrollable container.
     if (title.empty() && view) {
       RecordTaskAdditionResult(TaskModificationResult::kCancelled);
-      task_items_container_view_->RemoveChildViewT(view.get());
+
+      // Removing the task immediately may cause a crash when the task is saved
+      // in response to the task title textfield losing focus, as it may result
+      // in deleting focused view while the focus manager is handling focus
+      // change to another view. b/324409607
+      base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
+          FROM_HERE, base::BindOnce(&GlanceablesTasksView::RemoveTaskView,
+                                    weak_ptr_factory_.GetWeakPtr(), view));
       return;
     }
 
@@ -560,6 +559,19 @@
   }
 }
 
+void GlanceablesTasksView::RemoveTaskView(
+    base::WeakPtr<GlanceablesTaskViewV2> task_view) {
+  if (!task_view) {
+    return;
+  }
+
+  if (task_view->Contains(GetFocusManager()->GetFocusedView())) {
+    add_new_task_button_->RequestFocus();
+  }
+  task_items_container_view_->RemoveChildViewT(task_view.get());
+  PreferredSizeChanged();
+}
+
 BEGIN_METADATA(GlanceablesTasksView)
 END_METADATA
 
diff --git a/ash/glanceables/tasks/glanceables_tasks_view.h b/ash/glanceables/tasks/glanceables_tasks_view.h
index 1a0a41d..3a4ae6d 100644
--- a/ash/glanceables/tasks/glanceables_tasks_view.h
+++ b/ash/glanceables/tasks/glanceables_tasks_view.h
@@ -130,6 +130,9 @@
   // `error_type`.
   std::u16string GetErrorString(GlanceablesTasksErrorType error_type) const;
 
+  // Removes `task_view` from the tasks container.
+  void RemoveTaskView(base::WeakPtr<GlanceablesTaskViewV2> task_view);
+
   // Model for the combobox used to change the active task list.
   std::unique_ptr<TasksComboboxModel> tasks_combobox_model_;
 
diff --git a/ash/glanceables/tasks/glanceables_tasks_view_unittest.cc b/ash/glanceables/tasks/glanceables_tasks_view_unittest.cc
index cb2ae83c..39c8916 100644
--- a/ash/glanceables/tasks/glanceables_tasks_view_unittest.cc
+++ b/ash/glanceables/tasks/glanceables_tasks_view_unittest.cc
@@ -258,6 +258,7 @@
   PressAndReleaseKey(ui::VKEY_E);
   PressAndReleaseKey(ui::VKEY_W);
   PressAndReleaseKey(ui::VKEY_ESCAPE);
+  base::RunLoop().RunUntilIdle();
 
   // Verify executed callbacks number.
   EXPECT_EQ(tasks_client()->RunPendingAddTaskCallbacks(), 1u);
@@ -274,6 +275,7 @@
   GetEventGenerator()->PressAndReleaseKey(ui::VKEY_SPACE);
   GetEventGenerator()->PressAndReleaseKey(ui::VKEY_1);
   PressAndReleaseKey(ui::VKEY_ESCAPE);
+  base::RunLoop().RunUntilIdle();
 
   // Verify executed callbacks number.
   EXPECT_EQ(tasks_client()->RunPendingAddTaskCallbacks(), 0u);
@@ -287,6 +289,96 @@
       "Ash.Glanceables.TimeManagement.Tasks.UserAction", 4, 1);
 }
 
+TEST_F(GlanceablesTasksViewTest, TabbingOutOfNewTaskTextfieldAddsTask) {
+  base::HistogramTester histogram_tester;
+  tasks_client()->set_paused(true);
+
+  // Add a task.
+  GestureTapOn(GetAddNewTaskButton());
+
+  const auto* task_view = GetTaskItemsContainerView()->children()[0].get();
+  EXPECT_TRUE(task_view->GetViewByID(
+      base::to_underlying(GlanceablesViewId::kTaskItemTitleTextField)));
+
+  PressAndReleaseKey(ui::VKEY_N, ui::EF_SHIFT_DOWN);
+  PressAndReleaseKey(ui::VKEY_E);
+  PressAndReleaseKey(ui::VKEY_W);
+  PressAndReleaseKey(ui::VKEY_TAB);
+  base::RunLoop().RunUntilIdle();
+
+  // Verify that edit in browser button is visible and focused.
+  const auto* const edit_in_browser_button = GetEditInBrowserButton();
+  ASSERT_TRUE(edit_in_browser_button);
+  EXPECT_TRUE(edit_in_browser_button->GetVisible());
+  EXPECT_TRUE(edit_in_browser_button->HasFocus());
+
+  EXPECT_FALSE(task_view->GetViewByID(
+      base::to_underlying(GlanceablesViewId::kTaskItemTitleLabel)));
+
+  // Verify executed callbacks number.
+  EXPECT_EQ(tasks_client()->RunPendingAddTaskCallbacks(), 1u);
+  EXPECT_EQ(tasks_client()->RunPendingUpdateTaskCallbacks(), 0u);
+
+  // Tab back to the Add task textfield, and update the text.
+  PressAndReleaseKey(ui::VKEY_TAB, ui::EF_SHIFT_DOWN);
+  base::RunLoop().RunUntilIdle();
+
+  const auto* const title_text_field =
+      views::AsViewClass<views::Textfield>(task_view->GetViewByID(
+          base::to_underlying(GlanceablesViewId::kTaskItemTitleTextField)));
+  ASSERT_TRUE(title_text_field);
+  EXPECT_TRUE(title_text_field->HasFocus());
+  EXPECT_EQ(u"New", title_text_field->GetText());
+
+  PressAndReleaseKey(ui::VKEY_RIGHT);
+  PressAndReleaseKey(ui::VKEY_1);
+  // Focus edit in browser button.
+  PressAndReleaseKey(ui::VKEY_TAB);
+
+  EXPECT_EQ(tasks_client()->RunPendingAddTaskCallbacks(), 0u);
+  EXPECT_EQ(tasks_client()->RunPendingUpdateTaskCallbacks(), 1u);
+
+  // Focus the next task, which exits the task editing state.
+  PressAndReleaseKey(ui::VKEY_TAB);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_FALSE(GetEditInBrowserButton());
+
+  task_view = GetTaskItemsContainerView()->children()[0].get();
+  EXPECT_FALSE(task_view->GetViewByID(
+      base::to_underlying(GlanceablesViewId::kTaskItemTitleTextField)));
+  const auto* title_label =
+      views::AsViewClass<views::Label>(task_view->GetViewByID(
+          base::to_underlying(GlanceablesViewId::kTaskItemTitleLabel)));
+  ASSERT_TRUE(title_label);
+  EXPECT_EQ(u"New1", title_label->GetText());
+
+  // Edit the same task.
+  view()->GetWidget()->LayoutRootViewIfNecessary();
+  GestureTapOn(title_label);
+  GetEventGenerator()->PressAndReleaseKey(ui::VKEY_SPACE);
+  GetEventGenerator()->PressAndReleaseKey(ui::VKEY_1);
+  PressAndReleaseKey(ui::VKEY_ESCAPE);
+  base::RunLoop().RunUntilIdle();
+
+  // Verify executed callbacks number.
+  EXPECT_EQ(tasks_client()->RunPendingAddTaskCallbacks(), 0u);
+  EXPECT_EQ(tasks_client()->RunPendingUpdateTaskCallbacks(), 1u);
+
+  title_label = views::AsViewClass<views::Label>(
+      GetTaskItemsContainerView()->children()[0]->GetViewByID(
+          base::to_underlying(GlanceablesViewId::kTaskItemTitleLabel)));
+  ASSERT_TRUE(title_label);
+  EXPECT_EQ(u"New1 1", title_label->GetText());
+
+  histogram_tester.ExpectTotalCount(
+      "Ash.Glanceables.TimeManagement.Tasks.UserAction", 2);
+  histogram_tester.ExpectBucketCount(
+      "Ash.Glanceables.TimeManagement.Tasks.UserAction", 3, 1);
+  histogram_tester.ExpectBucketCount(
+      "Ash.Glanceables.TimeManagement.Tasks.UserAction", 4, 1);
+}
+
 TEST_F(GlanceablesTasksViewTest, AllowsPressingAddNewTaskButtonWhileAdding) {
   const auto initial_tasks_count =
       GetTaskItemsContainerView()->children().size();
@@ -306,6 +398,8 @@
   EXPECT_EQ(GetTaskItemsContainerView()->children().size(),
             initial_tasks_count + 2);
 
+  base::RunLoop().RunUntilIdle();
+
   // But the previous task becomes automatically committed due to losing focus.
   const auto* const previous_task_label = views::AsViewClass<views::Label>(
       GetTaskItemsContainerView()->children()[1]->GetViewByID(
@@ -359,6 +453,8 @@
 
     // Commit changes.
     PressAndReleaseKey(ui::VKEY_ESCAPE);
+
+    base::RunLoop().RunUntilIdle();
   }
 
   {
@@ -385,6 +481,7 @@
   EXPECT_EQ(GetTaskItemsContainerView()->children().size(),
             initial_tasks_count + 1);
   PressAndReleaseKey(ui::VKEY_ESCAPE);
+  base::RunLoop().RunUntilIdle();
 
   // Verify executed callbacks number.
   EXPECT_EQ(GetTaskItemsContainerView()->children().size(),
@@ -422,6 +519,7 @@
   PressAndReleaseKey(ui::VKEY_E);
   PressAndReleaseKey(ui::VKEY_W);
   PressAndReleaseKey(ui::VKEY_ESCAPE);
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(task_items_container_view->children().size(), 3u);
   EXPECT_FALSE(GetErrorMessage());
@@ -450,6 +548,7 @@
   GetEventGenerator()->PressAndReleaseKey(ui::VKEY_P);
   GetEventGenerator()->PressAndReleaseKey(ui::VKEY_D);
   PressAndReleaseKey(ui::VKEY_ESCAPE);
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(task_items_container_view->children().size(), 2u);
   EXPECT_FALSE(GetErrorMessage());
diff --git a/ash/picker/model/picker_search_results_section.h b/ash/picker/model/picker_search_results_section.h
index 4ad116e..508d972 100644
--- a/ash/picker/model/picker_search_results_section.h
+++ b/ash/picker/model/picker_search_results_section.h
@@ -19,6 +19,7 @@
   kExpressions,
   kLinks,
   kFiles,
+  kDriveFiles,
   kGifs,
   kRecentlyUsed,
 };
diff --git a/ash/picker/picker_controller.cc b/ash/picker/picker_controller.cc
index af3cf654..c19e1b1 100644
--- a/ash/picker/picker_controller.cc
+++ b/ash/picker/picker_controller.cc
@@ -18,10 +18,13 @@
 #include "ash/picker/picker_asset_fetcher_impl.h"
 #include "ash/picker/picker_copy_media.h"
 #include "ash/picker/picker_insert_media_request.h"
+#include "ash/picker/picker_rich_media.h"
 #include "ash/picker/picker_search_controller.h"
 #include "ash/picker/views/picker_icons.h"
+#include "ash/picker/views/picker_positioning.h"
 #include "ash/picker/views/picker_view.h"
 #include "ash/picker/views/picker_view_delegate.h"
+#include "ash/picker/views/picker_widget.h"
 #include "ash/public/cpp/ash_web_view_factory.h"
 #include "ash/public/cpp/picker/picker_client.h"
 #include "ash/public/cpp/picker/picker_search_result.h"
@@ -65,8 +68,7 @@
 constexpr base::TimeDelta kInsertMediaTimeout = base::Seconds(2);
 
 // Time from when a start starts to when the first set of results are published.
-// TODO: b/325195938 - Lower this to 200ms without affecting results.
-constexpr base::TimeDelta kBurnInPeriod = base::Milliseconds(400);
+constexpr base::TimeDelta kBurnInPeriod = base::Milliseconds(200);
 
 enum class PickerFeatureKeyType { kNone, kDev, kTest };
 
@@ -112,30 +114,29 @@
              : gfx::Rect();
 }
 
-std::optional<PickerInsertMediaRequest::MediaData> ResultToInsertMediaData(
+std::optional<PickerRichMedia> ResultToInsertMediaData(
     const PickerSearchResult& result) {
-  using ReturnType = std::optional<PickerInsertMediaRequest::MediaData>;
+  using ReturnType = std::optional<PickerRichMedia>;
   return std::visit(
       base::Overloaded{
           [](const PickerSearchResult::TextData& data) -> ReturnType {
-            return PickerInsertMediaRequest::MediaData::Text(data.text);
+            return PickerTextMedia(data.text);
           },
           [](const PickerSearchResult::EmojiData& data) -> ReturnType {
-            return PickerInsertMediaRequest::MediaData::Text(data.emoji);
+            return PickerTextMedia(data.emoji);
           },
           [](const PickerSearchResult::SymbolData& data) -> ReturnType {
-            return PickerInsertMediaRequest::MediaData::Text(data.symbol);
+            return PickerTextMedia(data.symbol);
           },
           [](const PickerSearchResult::EmoticonData& data) -> ReturnType {
-            return PickerInsertMediaRequest::MediaData::Text(data.emoticon);
+            return PickerTextMedia(data.emoticon);
           },
           [](const PickerSearchResult::GifData& data) -> ReturnType {
-            return PickerInsertMediaRequest::MediaData::Image(data.url);
+            return PickerImageMedia(data.full_url, data.full_dimensions,
+                                    data.content_description);
           },
           [](const PickerSearchResult::BrowsingHistoryData& data)
-              -> ReturnType {
-            return PickerInsertMediaRequest::MediaData::Link(data.url);
-          },
+              -> ReturnType { return PickerLinkMedia(data.url); },
           [](const PickerSearchResult::CategoryData& data) -> ReturnType {
             return std::nullopt;
           },
@@ -143,13 +144,6 @@
       result.data());
 }
 
-void MaybeCopyMediaToClipboard(const PickerSearchResult& result) {
-  if (const auto* gif =
-          std::get_if<PickerSearchResult::GifData>(&result.data())) {
-    CopyGifMediaToClipboard(gif->url, gif->content_description);
-  }
-}
-
 }  // namespace
 
 PickerController::PickerController() {
@@ -204,9 +198,11 @@
   if (widget_) {
     widget_->Close();
   } else {
-    widget_ = PickerView::CreateWidget(GetCaretBounds(), GetCursorPoint(),
-                                       GetFocusedWindowBounds(), this,
-                                       trigger_event_timestamp);
+    widget_ = PickerWidget::Create(
+        this,
+        GetPickerAnchorBounds(GetCaretBounds(), GetCursorPoint(),
+                              GetFocusedWindowBounds()),
+        trigger_event_timestamp);
     widget_->Show();
 
     feature_usage_metrics_.StartUsage();
@@ -265,14 +261,14 @@
     return;
   }
 
-  std::optional<PickerInsertMediaRequest::MediaData> media_to_insert =
+  std::optional<PickerRichMedia> media_to_insert =
       ResultToInsertMediaData(result);
   CHECK(media_to_insert.has_value());
 
   // This cancels the previous request if there was one.
   insert_media_request_ = std::make_unique<PickerInsertMediaRequest>(
       input_method, *media_to_insert, kInsertMediaTimeout,
-      base::BindOnce(&MaybeCopyMediaToClipboard, result));
+      base::BindOnce(&CopyMediaToClipboard, *media_to_insert));
 }
 
 PickerAssetFetcher* PickerController::GetAssetFetcher() {
diff --git a/ash/picker/picker_controller_unittest.cc b/ash/picker/picker_controller_unittest.cc
index 5d8ab05..980c942 100644
--- a/ash/picker/picker_controller_unittest.cc
+++ b/ash/picker/picker_controller_unittest.cc
@@ -21,6 +21,7 @@
 #include "ui/base/ime/fake_text_input_client.h"
 #include "ui/base/ime/input_method.h"
 #include "ui/base/models/image_model.h"
+#include "ui/gfx/geometry/size.h"
 #include "ui/views/test/widget_test.h"
 
 namespace ash {
@@ -67,6 +68,7 @@
                       FetchGifsCallback callback) override {}
   void StopGifSearch() override {}
   void StartCrosSearch(const std::u16string& query,
+                       std::optional<PickerCategory> category,
                        CrosSearchResultsCallback callback) override {}
   void StopCrosQuery() override {}
 
@@ -178,8 +180,9 @@
       Shell::GetPrimaryRootWindow()->GetHost()->GetInputMethod();
 
   controller.InsertResultOnNextFocus(PickerSearchResult::Gif(
-      GURL("http://foo.com/fake.gif"),
+      GURL("http://foo.com/fake_preview.gif"),
       GURL("http://foo.com/fake_preview_image.png"), gfx::Size(),
+      GURL("http://foo.com/fake.gif"), gfx::Size(),
       /*content_description=*/u""));
   controller.widget_for_testing()->CloseNow();
   ui::FakeTextInputClient input_field(
@@ -199,7 +202,9 @@
       Shell::GetPrimaryRootWindow()->GetHost()->GetInputMethod();
 
   controller.InsertResultOnNextFocus(PickerSearchResult::Gif(
-      /*url=*/GURL("http://foo.com"), /*preview_image_url=*/GURL(), gfx::Size(),
+      /*preview_url=*/GURL("http://foo.com/preview"),
+      /*preview_image_url=*/GURL(), gfx::Size(30, 20),
+      /*full_url=*/GURL("http://foo.com"), gfx::Size(60, 40),
       /*content_description=*/u"a gif"));
   controller.widget_for_testing()->CloseNow();
   ui::FakeTextInputClient input_field(
@@ -209,7 +214,7 @@
 
   EXPECT_EQ(
       ReadHtmlFromClipboard(ui::Clipboard::GetForCurrentThread()),
-      uR"html(<img src="http://foo.com/" referrerpolicy="no-referrer" alt="a gif"/>)html");
+      uR"html(<img src="http://foo.com/" referrerpolicy="no-referrer" alt="a gif" width="60" height="40"/>)html");
   EXPECT_TRUE(
       ash::ToastManager::Get()->IsToastShown("picker_copy_to_clipboard"));
 }
diff --git a/ash/picker/picker_copy_media.cc b/ash/picker/picker_copy_media.cc
index 8fe13fd..0a14e8e 100644
--- a/ash/picker/picker_copy_media.cc
+++ b/ash/picker/picker_copy_media.cc
@@ -4,16 +4,24 @@
 
 #include "ash/picker/picker_copy_media.h"
 
+#include <iterator>
 #include <memory>
 #include <string>
+#include <vector>
 
 #include "ash/constants/notifier_catalogs.h"
+#include "ash/picker/picker_rich_media.h"
 #include "ash/public/cpp/system/toast_data.h"
 #include "ash/public/cpp/system/toast_manager.h"
+#include "base/functional/overloaded.h"
+#include "base/ranges/algorithm.h"
 #include "base/strings/escape.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
+#include "ui/gfx/geometry/size.h"
 #include "url/gurl.h"
 
 namespace ash {
@@ -21,27 +29,70 @@
 
 constexpr char kPickerCopyToClipboardToastId[] = "picker_copy_to_clipboard";
 
-std::string BuildGifHTML(const GURL& url,
-                         std::u16string_view content_description) {
+struct HtmlAttr {
+  // `name` has to be a compile-time constant.
+  const char* name;
+  std::string value;
+};
+
+std::string ImageHtmlAttrsToStr(std::vector<HtmlAttr> attrs) {
+  std::vector<std::string> attrs_as_strings;
+  attrs_as_strings.reserve(attrs.size());
+  base::ranges::transform(
+      std::move(attrs), std::back_inserter(attrs_as_strings),
+      [](HtmlAttr attr) {
+        return base::StringPrintf(R"(%s="%s")", attr.name, attr.value.c_str());
+      });
+
+  return base::StringPrintf(
+      R"(<img %s/>)",
+      base::JoinString(std::move(attrs_as_strings), " ").c_str());
+}
+
+std::string BuildImageHtml(const PickerImageMedia& image) {
+  std::vector<HtmlAttr> attrs;
+  // GURL::specs are always canonicalised and escaped, so this cannot result in
+  // an XSS.
+  attrs.emplace_back("src", image.url.spec());
   // Referrer-Policy is used to prevent the website from getting information
   // about where the GIFs are being used.
-  return base::StringPrintf(
-      R"html(<img src="%s" referrerpolicy="no-referrer" alt="%s"/>)html",
-      url.spec().c_str(),
-      base::EscapeForHTML(base::UTF16ToUTF8(content_description)).c_str());
+  attrs.emplace_back("referrerpolicy", "no-referrer");
+  if (!image.content_description.empty()) {
+    attrs.emplace_back(
+        "alt",
+        base::EscapeForHTML(base::UTF16ToUTF8(image.content_description)));
+  }
+  if (image.dimensions.has_value()) {
+    attrs.emplace_back("width",
+                       base::NumberToString(image.dimensions->width()));
+    attrs.emplace_back("height",
+                       base::NumberToString(image.dimensions->height()));
+  }
+  return ImageHtmlAttrsToStr(std::move(attrs));
 }
 
 }  // namespace
 
-void CopyGifMediaToClipboard(const GURL& url,
-                             std::u16string_view content_description) {
-  // Overwrite the clipboard data with the GIF url.
+void CopyMediaToClipboard(const PickerRichMedia& media) {
   auto clipboard = std::make_unique<ui::ScopedClipboardWriter>(
       ui::ClipboardBuffer::kCopyPaste);
 
-  clipboard->WriteHTML(
-      base::UTF8ToUTF16(BuildGifHTML(url, content_description)),
-      /*document_url=*/"");
+  // Overwrite the clipboard data.
+  std::visit(base::Overloaded{
+                 [&clipboard](const PickerTextMedia& media) {
+                   clipboard->WriteText(std::move(media.text));
+                 },
+                 [&clipboard](const PickerImageMedia& media) {
+                   clipboard->WriteHTML(
+                       base::UTF8ToUTF16(BuildImageHtml(media)),
+                       /*document_url=*/"");
+                 },
+                 [&clipboard](const PickerLinkMedia& media) {
+                   // TODO(b/322729192): Copy a real hyperlink.
+                   clipboard->WriteText(base::UTF8ToUTF16(media.url.spec()));
+                 },
+             },
+             media);
 
   // Show a toast to inform the user about the copy.
   // TODO: b/322928125 - Use dedicated toast catalog name.
diff --git a/ash/picker/picker_copy_media.h b/ash/picker/picker_copy_media.h
index d085e60..5e65b478 100644
--- a/ash/picker/picker_copy_media.h
+++ b/ash/picker/picker_copy_media.h
@@ -8,16 +8,12 @@
 #include <string_view>
 
 #include "ash/ash_export.h"
-
-class GURL;
+#include "ash/picker/picker_rich_media.h"
 
 namespace ash {
 
-// Copies a GIF into the clipboard.
-// TODO: b/322928125 - Take a PickerInsertMediaRequest::MediaData instead.
-ASH_EXPORT void CopyGifMediaToClipboard(
-    const GURL& url,
-    std::u16string_view content_description);
+// Copies rich media into the clipboard.
+ASH_EXPORT void CopyMediaToClipboard(const PickerRichMedia& media);
 
 }  // namespace ash
 
diff --git a/ash/picker/picker_copy_media_unittest.cc b/ash/picker/picker_copy_media_unittest.cc
index 2c2c05f..56c9a143 100644
--- a/ash/picker/picker_copy_media_unittest.cc
+++ b/ash/picker/picker_copy_media_unittest.cc
@@ -4,38 +4,87 @@
 
 #include "ash/picker/picker_copy_media.h"
 
+#include "ash/picker/picker_rich_media.h"
 #include "ash/picker/picker_test_util.h"
 #include "ash/public/cpp/system/toast_manager.h"
 #include "ash/test/ash_test_base.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/clipboard/clipboard.h"
+#include "ui/gfx/geometry/size.h"
 
 namespace ash {
 namespace {
 
 class PickerCopyMediaTest : public AshTestBase {};
 
-TEST_F(PickerCopyMediaTest, CopiesGifAsHtml) {
-  CopyGifMediaToClipboard(GURL("https://foo.com"),
-                          /*content_description=*/u"a gif");
+TEST_F(PickerCopyMediaTest, CopiesText) {
+  CopyMediaToClipboard(PickerTextMedia(u"hello"));
+
+  EXPECT_EQ(ReadTextFromClipboard(ui::Clipboard::GetForCurrentThread()),
+            u"hello");
+}
+
+TEST_F(PickerCopyMediaTest, ShowsToastAfterCopyingText) {
+  CopyMediaToClipboard(PickerTextMedia(u"hello"));
+
+  EXPECT_TRUE(
+      ash::ToastManager::Get()->IsToastShown("picker_copy_to_clipboard"));
+}
+
+TEST_F(PickerCopyMediaTest, CopiesImageWithKnownDimensionsAsHtml) {
+  CopyMediaToClipboard(
+      PickerImageMedia(GURL("https://foo.com"), gfx::Size(30, 20)));
 
   EXPECT_EQ(
       ReadHtmlFromClipboard(ui::Clipboard::GetForCurrentThread()),
-      uR"html(<img src="https://foo.com/" referrerpolicy="no-referrer" alt="a gif"/>)html");
+      uR"html(<img src="https://foo.com/" referrerpolicy="no-referrer" width="30" height="20"/>)html");
 }
 
-TEST_F(PickerCopyMediaTest, EscapesAltText) {
-  CopyGifMediaToClipboard(GURL("https://foo.com"),
-                          /*content_description=*/u"a \"gif\"");
+TEST_F(PickerCopyMediaTest, CopiesImageWithUnknownDimensionsAsHtml) {
+  CopyMediaToClipboard(PickerImageMedia(GURL("https://foo.com")));
 
   EXPECT_EQ(
       ReadHtmlFromClipboard(ui::Clipboard::GetForCurrentThread()),
-      uR"html(<img src="https://foo.com/" referrerpolicy="no-referrer" alt="a &quot;gif&quot;"/>)html");
+      uR"html(<img src="https://foo.com/" referrerpolicy="no-referrer"/>)html");
 }
 
-TEST_F(PickerCopyMediaTest, ShowsToast) {
-  CopyGifMediaToClipboard(GURL("https://foo.com"),
-                          /*content_description=*/u"a gif");
+TEST_F(PickerCopyMediaTest, CopiesImagesWithBothAltTextAndDimensionsAsHtml) {
+  CopyMediaToClipboard(PickerImageMedia(GURL("https://foo.com"),
+                                        gfx::Size(30, 20),
+                                        /*content_description=*/u"img"));
+
+  EXPECT_EQ(
+      ReadHtmlFromClipboard(ui::Clipboard::GetForCurrentThread()),
+      uR"html(<img src="https://foo.com/" referrerpolicy="no-referrer" alt="img" width="30" height="20"/>)html");
+}
+
+TEST_F(PickerCopyMediaTest, EscapesAltTextForImages) {
+  CopyMediaToClipboard(PickerImageMedia(GURL("https://foo.com"),
+                                        /*dimensions=*/std::nullopt,
+                                        /*content_description=*/u"\"img\""));
+
+  EXPECT_EQ(
+      ReadHtmlFromClipboard(ui::Clipboard::GetForCurrentThread()),
+      uR"html(<img src="https://foo.com/" referrerpolicy="no-referrer" alt="&quot;img&quot;"/>)html");
+}
+
+TEST_F(PickerCopyMediaTest, ShowsToastAfterCopyingImage) {
+  CopyMediaToClipboard(
+      PickerImageMedia(GURL("https://foo.com"), gfx::Size(30, 20)));
+
+  EXPECT_TRUE(
+      ash::ToastManager::Get()->IsToastShown("picker_copy_to_clipboard"));
+}
+
+TEST_F(PickerCopyMediaTest, CopiesLinks) {
+  CopyMediaToClipboard(PickerLinkMedia(GURL("https://foo.com")));
+
+  EXPECT_EQ(ReadTextFromClipboard(ui::Clipboard::GetForCurrentThread()),
+            u"https://foo.com/");
+}
+
+TEST_F(PickerCopyMediaTest, ShowsToastAfterCopyingLink) {
+  CopyMediaToClipboard(PickerLinkMedia(GURL("https://foo.com")));
 
   EXPECT_TRUE(
       ash::ToastManager::Get()->IsToastShown("picker_copy_to_clipboard"));
diff --git a/ash/picker/picker_insert_media.cc b/ash/picker/picker_insert_media.cc
new file mode 100644
index 0000000..53d61df
--- /dev/null
+++ b/ash/picker/picker_insert_media.cc
@@ -0,0 +1,47 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/picker/picker_insert_media.h"
+
+#include "ash/picker/picker_rich_media.h"
+#include "base/functional/overloaded.h"
+#include "base/strings/utf_string_conversions.h"
+#include "ui/base/ime/text_input_client.h"
+#include "url/gurl.h"
+
+namespace ash {
+
+bool InsertMediaToInputField(PickerRichMedia media,
+                             ui::TextInputClient* client) {
+  if (client == nullptr) {
+    return false;
+  }
+
+  return std::visit(
+      base::Overloaded{
+          [client](PickerTextMedia media) {
+            client->InsertText(media.text,
+                               ui::TextInputClient::InsertTextCursorBehavior::
+                                   kMoveCursorAfterText);
+            return true;
+          },
+          [client](PickerImageMedia media) {
+            if (!client->CanInsertImage()) {
+              return false;
+            }
+            client->InsertImage(media.url);
+            return true;
+          },
+          [client](PickerLinkMedia media) {
+            // TODO(b/322729192): Insert a real hyperlink.
+            client->InsertText(base::UTF8ToUTF16(media.url.spec()),
+                               ui::TextInputClient::InsertTextCursorBehavior::
+                                   kMoveCursorAfterText);
+            return true;
+          },
+      },
+      std::move(media));
+}
+
+}  // namespace ash
diff --git a/ash/picker/picker_insert_media.h b/ash/picker/picker_insert_media.h
new file mode 100644
index 0000000..c98ed45
--- /dev/null
+++ b/ash/picker/picker_insert_media.h
@@ -0,0 +1,25 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_PICKER_PICKER_INSERT_MEDIA_H_
+#define ASH_PICKER_PICKER_INSERT_MEDIA_H_
+
+#include "ash/ash_export.h"
+#include "ash/picker/picker_rich_media.h"
+
+namespace ui {
+class TextInputClient;
+}  // namespace ui
+
+namespace ash {
+
+// Inserts `media` into `client`.
+// Returns whether the insertion was successful.
+[[nodiscard]] ASH_EXPORT bool InsertMediaToInputField(
+    PickerRichMedia media,
+    ui::TextInputClient* client);
+
+}  // namespace ash
+
+#endif  // ASH_PICKER_PICKER_INSERT_MEDIA_REQUEST_H_
diff --git a/ash/picker/picker_insert_media_request.cc b/ash/picker/picker_insert_media_request.cc
index 098d04f..405b9917 100644
--- a/ash/picker/picker_insert_media_request.cc
+++ b/ash/picker/picker_insert_media_request.cc
@@ -4,6 +4,8 @@
 
 #include "ash/picker/picker_insert_media_request.h"
 
+#include "ash/picker/picker_insert_media.h"
+#include "ash/picker/picker_rich_media.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "ui/base/ime/input_method.h"
@@ -12,64 +14,12 @@
 
 namespace ash {
 
-PickerInsertMediaRequest::MediaData PickerInsertMediaRequest::MediaData::Text(
-    std::u16string_view text) {
-  return MediaData(MediaData::Type::kText, std::u16string(text));
-}
-
-PickerInsertMediaRequest::MediaData PickerInsertMediaRequest::MediaData::Text(
-    std::string_view text) {
-  return MediaData(MediaData::Type::kText, base::UTF8ToUTF16(text));
-}
-
-PickerInsertMediaRequest::MediaData PickerInsertMediaRequest::MediaData::Image(
-    const GURL& url) {
-  return MediaData(MediaData::Type::kImage, url);
-}
-
-PickerInsertMediaRequest::MediaData PickerInsertMediaRequest::MediaData::Link(
-    const GURL& url) {
-  return MediaData(MediaData::Type::kLink, url);
-}
-
-PickerInsertMediaRequest::MediaData::MediaData(const MediaData&) = default;
-
-PickerInsertMediaRequest::MediaData&
-PickerInsertMediaRequest::MediaData::operator=(const MediaData&) = default;
-
-PickerInsertMediaRequest::MediaData::~MediaData() = default;
-
-bool PickerInsertMediaRequest::MediaData::Insert(ui::TextInputClient* client) {
-  switch (type_) {
-    case MediaData::Type::kText:
-      client->InsertText(
-          std::get<std::u16string>(data_),
-          ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
-      return true;
-    case MediaData::Type::kImage:
-      if (!client->CanInsertImage()) {
-        return false;
-      }
-      client->InsertImage(std::get<GURL>(data_));
-      return true;
-    case MediaData::Type::kLink:
-      // TODO(b/322729192): Insert a real hyperlink.
-      client->InsertText(
-          base::UTF8ToUTF16(std::get<GURL>(data_).spec()),
-          ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
-      return true;
-  }
-}
-
-PickerInsertMediaRequest::MediaData::MediaData(Type type, Data data)
-    : type_(type), data_(std::move(data)) {}
-
 PickerInsertMediaRequest::PickerInsertMediaRequest(
     ui::InputMethod* input_method,
-    const MediaData& data_to_insert,
+    const PickerRichMedia& media_to_insert,
     const base::TimeDelta insert_timeout,
     InsertFailedCallback insert_failed_callback)
-    : data_to_insert(data_to_insert),
+    : media_to_insert_(media_to_insert),
       insert_failed_callback_(std::move(insert_failed_callback)) {
   observation_.Observe(input_method);
   insert_timeout_timer_.Start(FROM_HERE, insert_timeout, this,
@@ -85,18 +35,18 @@
   if (mutable_client == nullptr ||
       mutable_client->GetTextInputType() ==
           ui::TextInputType::TEXT_INPUT_TYPE_NONE ||
-      !data_to_insert.has_value()) {
+      !media_to_insert_.has_value()) {
     return;
   }
 
   DCHECK_EQ(mutable_client, client);
-  if (!data_to_insert->Insert(mutable_client)) {
+  if (!InsertMediaToInputField(*media_to_insert_, mutable_client)) {
     if (!insert_failed_callback_.is_null()) {
       std::move(insert_failed_callback_).Run();
     }
   }
 
-  data_to_insert = std::nullopt;
+  media_to_insert_ = std::nullopt;
   observation_.Reset();
 }
 
@@ -108,11 +58,13 @@
 }
 
 void PickerInsertMediaRequest::CancelPendingInsert() {
-  data_to_insert = std::nullopt;
   observation_.Reset();
 
-  if (!insert_failed_callback_.is_null()) {
-    std::move(insert_failed_callback_).Run();
+  if (media_to_insert_.has_value()) {
+    media_to_insert_ = std::nullopt;
+    if (!insert_failed_callback_.is_null()) {
+      std::move(insert_failed_callback_).Run();
+    }
   }
 }
 
diff --git a/ash/picker/picker_insert_media_request.h b/ash/picker/picker_insert_media_request.h
index 2f01e62..05ab8198 100644
--- a/ash/picker/picker_insert_media_request.h
+++ b/ash/picker/picker_insert_media_request.h
@@ -9,6 +9,7 @@
 #include <variant>
 
 #include "ash/ash_export.h"
+#include "ash/picker/picker_rich_media.h"
 #include "base/functional/callback_forward.h"
 #include "base/scoped_observation.h"
 #include "base/time/time.h"
@@ -26,32 +27,6 @@
 // Inserts rich media such as text and images into an input field.
 class ASH_EXPORT PickerInsertMediaRequest : public ui::InputMethodObserver {
  public:
-  class MediaData {
-   public:
-    static MediaData Text(std::u16string_view text);
-    static MediaData Text(std::string_view text);
-    static MediaData Image(const GURL& url);
-    static MediaData Link(const GURL& url);
-
-    MediaData(const MediaData&);
-    MediaData& operator=(const MediaData&);
-    ~MediaData();
-
-    // Inserts this media data into `client`.
-    // Returns whether the insertion was successful.
-    [[nodiscard]] bool Insert(ui::TextInputClient* client);
-
-   private:
-    enum class Type { kText, kImage, kLink };
-
-    using Data = std::variant<std::u16string, GURL>;
-
-    explicit MediaData(Type type, Data data);
-
-    Type type_;
-    Data data_;
-  };
-
   using InsertFailedCallback = base::OnceClosure;
 
   // Creates a request to insert `data` in the next focused input field.
@@ -62,7 +37,7 @@
   // not support inserting `data`, or no insertion happened before the timeout.
   explicit PickerInsertMediaRequest(
       ui::InputMethod* input_method,
-      const MediaData& data_to_insert,
+      const PickerRichMedia& media,
       base::TimeDelta insert_timeout,
       InsertFailedCallback insert_failed_callback = {});
   ~PickerInsertMediaRequest() override;
@@ -79,7 +54,7 @@
   // Does nothing if the insertion has already happened.
   void CancelPendingInsert();
 
-  std::optional<MediaData> data_to_insert;
+  std::optional<PickerRichMedia> media_to_insert_;
   base::ScopedObservation<ui::InputMethod, ui::InputMethodObserver>
       observation_{this};
   base::OneShotTimer insert_timeout_timer_;
diff --git a/ash/picker/picker_insert_media_request_unittest.cc b/ash/picker/picker_insert_media_request_unittest.cc
index d22afa7c..07ea01a 100644
--- a/ash/picker/picker_insert_media_request_unittest.cc
+++ b/ash/picker/picker_insert_media_request_unittest.cc
@@ -21,8 +21,8 @@
 constexpr base::TimeDelta kInsertionTimeout = base::Seconds(1);
 
 struct TestCase {
-  // The media data to insert.
-  PickerInsertMediaRequest::MediaData data_to_insert;
+  // The media to insert.
+  PickerRichMedia media_to_insert;
 
   // The expected text in the input field if the insertion was successful.
   std::u16string expected_text;
@@ -47,18 +47,16 @@
     PickerInsertMediaRequestTest,
     testing::Values(
         TestCase{
-            .data_to_insert =
-                PickerInsertMediaRequest::MediaData::Text(u"hello"),
+            .media_to_insert = PickerTextMedia(u"hello"),
             .expected_text = u"hello",
         },
         TestCase{
-            .data_to_insert = PickerInsertMediaRequest::MediaData::Image(
-                GURL("http://foo.com/fake.jpg")),
+            .media_to_insert = PickerImageMedia(GURL("http://foo.com/fake.jpg"),
+                                                gfx::Size(10, 10)),
             .expected_image_url = GURL("http://foo.com/fake.jpg"),
         },
         TestCase{
-            .data_to_insert = PickerInsertMediaRequest::MediaData::Link(
-                GURL("http://foo.com")),
+            .media_to_insert = PickerLinkMedia(GURL("http://foo.com")),
             .expected_text = u"http://foo.com/",
         }));
 
@@ -67,7 +65,7 @@
       {.type = ui::TEXT_INPUT_TYPE_TEXT, .can_insert_image = true});
   InputMethodAsh input_method(nullptr);
 
-  PickerInsertMediaRequest request(&input_method, GetParam().data_to_insert,
+  PickerInsertMediaRequest request(&input_method, GetParam().media_to_insert,
                                    /*insert_timeout=*/base::Seconds(1));
   task_environment().FastForwardBy(base::Seconds(1));
 
@@ -79,7 +77,7 @@
       {.type = ui::TEXT_INPUT_TYPE_TEXT, .can_insert_image = true});
   InputMethodAsh input_method(nullptr);
 
-  PickerInsertMediaRequest request(&input_method, GetParam().data_to_insert,
+  PickerInsertMediaRequest request(&input_method, GetParam().media_to_insert,
                                    kInsertionTimeout);
   input_method.SetFocusedTextInputClient(&client);
 
@@ -93,7 +91,7 @@
       {.type = ui::TEXT_INPUT_TYPE_TEXT, .can_insert_image = true});
   InputMethodAsh input_method(nullptr);
 
-  PickerInsertMediaRequest request(&input_method, GetParam().data_to_insert,
+  PickerInsertMediaRequest request(&input_method, GetParam().media_to_insert,
                                    /*insert_timeout=*/base::Seconds(1));
   task_environment().FastForwardBy(base::Milliseconds(999));
   input_method.SetFocusedTextInputClient(&client);
@@ -107,7 +105,7 @@
       {.type = ui::TEXT_INPUT_TYPE_TEXT, .can_insert_image = true});
   InputMethodAsh input_method(nullptr);
 
-  PickerInsertMediaRequest request(&input_method, GetParam().data_to_insert,
+  PickerInsertMediaRequest request(&input_method, GetParam().media_to_insert,
                                    /*insert_timeout=*/base::Seconds(1));
   task_environment().FastForwardBy(base::Seconds(1));
   input_method.SetFocusedTextInputClient(&client);
@@ -123,7 +121,7 @@
   InputMethodAsh input_method(nullptr);
   input_method.SetFocusedTextInputClient(&prev_client);
 
-  PickerInsertMediaRequest request(&input_method, GetParam().data_to_insert,
+  PickerInsertMediaRequest request(&input_method, GetParam().media_to_insert,
                                    kInsertionTimeout);
   input_method.SetFocusedTextInputClient(&next_client);
 
@@ -142,7 +140,7 @@
   InputMethodAsh input_method(nullptr);
   input_method.SetFocusedTextInputClient(&prev_client);
 
-  PickerInsertMediaRequest request(&input_method, GetParam().data_to_insert,
+  PickerInsertMediaRequest request(&input_method, GetParam().media_to_insert,
                                    /*insert_timeout=*/base::Seconds(1));
   task_environment().FastForwardBy(base::Milliseconds(999));
   input_method.SetFocusedTextInputClient(&next_client);
@@ -162,7 +160,7 @@
   InputMethodAsh input_method(nullptr);
   input_method.SetFocusedTextInputClient(&prev_client);
 
-  PickerInsertMediaRequest request(&input_method, GetParam().data_to_insert,
+  PickerInsertMediaRequest request(&input_method, GetParam().media_to_insert,
                                    /*insert_timeout=*/base::Seconds(1));
   task_environment().FastForwardBy(base::Seconds(1));
   input_method.SetFocusedTextInputClient(&next_client);
@@ -177,7 +175,7 @@
   InputMethodAsh input_method(nullptr);
 
   {
-    PickerInsertMediaRequest request(&input_method, GetParam().data_to_insert,
+    PickerInsertMediaRequest request(&input_method, GetParam().media_to_insert,
                                      kInsertionTimeout);
   }
   input_method.SetFocusedTextInputClient(&client);
@@ -191,7 +189,7 @@
       {.type = ui::TEXT_INPUT_TYPE_TEXT, .can_insert_image = true});
   InputMethodAsh input_method(nullptr);
 
-  PickerInsertMediaRequest request(&input_method, GetParam().data_to_insert,
+  PickerInsertMediaRequest request(&input_method, GetParam().media_to_insert,
                                    kInsertionTimeout);
   input_method.SetFocusedTextInputClient(&client_none);
   input_method.SetFocusedTextInputClient(&client_text);
@@ -207,7 +205,7 @@
       {.type = ui::TEXT_INPUT_TYPE_TEXT, .can_insert_image = true});
   InputMethodAsh input_method(nullptr);
 
-  PickerInsertMediaRequest request(&input_method, GetParam().data_to_insert,
+  PickerInsertMediaRequest request(&input_method, GetParam().media_to_insert,
                                    kInsertionTimeout);
   input_method.SetFocusedTextInputClient(&client1);
   input_method.SetFocusedTextInputClient(&client2);
@@ -221,7 +219,7 @@
       {.type = ui::TEXT_INPUT_TYPE_TEXT, .can_insert_image = true});
   InputMethodAsh input_method(nullptr);
 
-  PickerInsertMediaRequest request(&input_method, GetParam().data_to_insert,
+  PickerInsertMediaRequest request(&input_method, GetParam().media_to_insert,
                                    /*insert_timeout=*/base::Seconds(1));
   input_method.SetFocusedTextInputClient(&client);
   task_environment().FastForwardBy(base::Seconds(1));
@@ -236,7 +234,7 @@
   InputMethodAsh input_method(nullptr);
 
   {
-    PickerInsertMediaRequest request(&input_method, GetParam().data_to_insert,
+    PickerInsertMediaRequest request(&input_method, GetParam().media_to_insert,
                                      kInsertionTimeout);
     input_method.SetFocusedTextInputClient(&client);
   }
@@ -251,7 +249,7 @@
   auto old_input_method = std::make_unique<InputMethodAsh>(nullptr);
 
   PickerInsertMediaRequest request(
-      old_input_method.get(), GetParam().data_to_insert, kInsertionTimeout);
+      old_input_method.get(), GetParam().media_to_insert, kInsertionTimeout);
   old_input_method.reset();
   InputMethodAsh new_input_method(nullptr);
   new_input_method.SetFocusedTextInputClient(&client);
@@ -259,11 +257,27 @@
   EXPECT_EQ(client.text(), u"");
 }
 
+TEST_P(PickerInsertMediaRequestTest, DoesNotCallCallbackOnSuccess) {
+  InputMethodAsh input_method(nullptr);
+  ui::FakeTextInputClient client(
+      &input_method,
+      {.type = ui::TEXT_INPUT_TYPE_TEXT, .can_insert_image = true});
+
+  base::test::TestFuture<void> failure_future;
+  PickerInsertMediaRequest request(&input_method, GetParam().media_to_insert,
+                                   /*insert_timeout=*/base::Seconds(1),
+                                   failure_future.GetCallback());
+  client.Focus();
+  task_environment().FastForwardBy(base::Seconds(1));
+
+  EXPECT_FALSE(failure_future.IsReady());
+}
+
 TEST_P(PickerInsertMediaRequestTest, CallsFailureCallbackOnTimeout) {
   InputMethodAsh input_method(nullptr);
 
   base::test::TestFuture<void> failure_future;
-  PickerInsertMediaRequest request(&input_method, GetParam().data_to_insert,
+  PickerInsertMediaRequest request(&input_method, GetParam().media_to_insert,
                                    /*insert_timeout=*/base::Seconds(1),
                                    failure_future.GetCallback());
   task_environment().FastForwardBy(base::Seconds(1));
@@ -281,7 +295,7 @@
   base::test::TestFuture<void> failure_future;
   PickerInsertMediaRequest request(
       &input_method,
-      PickerInsertMediaRequest::MediaData::Image(GURL("http://foo.com")),
+      PickerImageMedia(GURL("http://foo.com"), gfx::Size(10, 10)),
       /*insert_timeout=*/base::Seconds(1), failure_future.GetCallback());
   input_method.SetFocusedTextInputClient(&client);
 
diff --git a/ash/picker/picker_insert_media_unittest.cc b/ash/picker/picker_insert_media_unittest.cc
new file mode 100644
index 0000000..6ebf360
--- /dev/null
+++ b/ash/picker/picker_insert_media_unittest.cc
@@ -0,0 +1,72 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/picker/picker_insert_media.h"
+
+#include <optional>
+#include <string>
+
+#include "ash/picker/picker_rich_media.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/ime/fake_text_input_client.h"
+
+namespace ash {
+namespace {
+
+struct TestCase {
+  // The media to insert.
+  PickerRichMedia media_to_insert;
+
+  // The expected text in the input field if the insertion was successful.
+  std::u16string expected_text;
+
+  // The expected image in the input field if the insertion was successful.
+  std::optional<GURL> expected_image_url;
+};
+
+using PickerInsertMediaTest = testing::TestWithParam<TestCase>;
+
+TEST_P(PickerInsertMediaTest, ReturnsFalseForNullClient) {
+  EXPECT_FALSE(InsertMediaToInputField(GetParam().media_to_insert,
+                                       /*client=*/nullptr));
+}
+
+TEST_P(PickerInsertMediaTest, InsertsOnNextFocusWhileFocused) {
+  ui::FakeTextInputClient client(
+      {.type = ui::TEXT_INPUT_TYPE_TEXT, .can_insert_image = true});
+
+  EXPECT_TRUE(InsertMediaToInputField(GetParam().media_to_insert, &client));
+  EXPECT_EQ(client.text(), GetParam().expected_text);
+  EXPECT_EQ(client.last_inserted_image_url(), GetParam().expected_image_url);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    ,
+    PickerInsertMediaTest,
+    testing::Values(
+        TestCase{
+            .media_to_insert = PickerTextMedia(u"hello"),
+            .expected_text = u"hello",
+        },
+        TestCase{
+            .media_to_insert = PickerImageMedia(GURL("http://foo.com/fake.jpg"),
+                                                gfx::Size(10, 10)),
+            .expected_image_url = GURL("http://foo.com/fake.jpg"),
+        },
+        TestCase{
+            .media_to_insert = PickerLinkMedia(GURL("http://foo.com")),
+            .expected_text = u"http://foo.com/",
+        }));
+
+TEST(PickerInsertMediaUnsupportedTest, InsertingUnsupportedImageReturnsFalse) {
+  ui::FakeTextInputClient client(
+      {.type = ui::TEXT_INPUT_TYPE_TEXT, .can_insert_image = false});
+
+  EXPECT_FALSE(InsertMediaToInputField(
+      PickerImageMedia(GURL("http://foo.com"), gfx::Size(10, 10)), &client));
+  EXPECT_EQ(client.last_inserted_image_url(), std::nullopt);
+}
+
+}  // namespace
+}  // namespace ash
diff --git a/ash/picker/picker_rich_media.cc b/ash/picker/picker_rich_media.cc
new file mode 100644
index 0000000..3d091aab
--- /dev/null
+++ b/ash/picker/picker_rich_media.cc
@@ -0,0 +1,29 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/picker/picker_rich_media.h"
+
+#include <memory>
+#include <string>
+
+#include "base/strings/utf_string_conversions.h"
+#include "url/gurl.h"
+
+namespace ash {
+
+PickerTextMedia::PickerTextMedia(std::u16string text) : text(std::move(text)) {}
+
+PickerTextMedia::PickerTextMedia(std::string_view text)
+    : PickerTextMedia(base::UTF8ToUTF16(text)) {}
+
+PickerImageMedia::PickerImageMedia(GURL url,
+                                   std::optional<gfx::Size> dimensions,
+                                   std::u16string content_description)
+    : url(std::move(url)),
+      dimensions(dimensions),
+      content_description(std::move(content_description)) {}
+
+PickerLinkMedia::PickerLinkMedia(GURL url) : url(std::move(url)) {}
+
+}  // namespace ash
diff --git a/ash/picker/picker_rich_media.h b/ash/picker/picker_rich_media.h
new file mode 100644
index 0000000..d9c99262
--- /dev/null
+++ b/ash/picker/picker_rich_media.h
@@ -0,0 +1,48 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_PICKER_PICKER_RICH_MEDIA_H_
+#define ASH_PICKER_PICKER_RICH_MEDIA_H_
+
+#include <string>
+#include <string_view>
+#include <variant>
+
+#include "ash/ash_export.h"
+#include "ui/gfx/geometry/size.h"
+#include "url/gurl.h"
+
+namespace ash {
+
+struct ASH_EXPORT PickerTextMedia {
+  std::u16string text;
+
+  explicit PickerTextMedia(std::u16string text);
+  explicit PickerTextMedia(std::string_view text);
+};
+
+struct ASH_EXPORT PickerImageMedia {
+  GURL url;
+  // `dimensions` is std::nullopt if it's unknown.
+  std::optional<gfx::Size> dimensions;
+  std::u16string content_description;
+
+  explicit PickerImageMedia(GURL url,
+                            std::optional<gfx::Size> dimensions = std::nullopt,
+                            std::u16string content_description = u"");
+};
+
+struct ASH_EXPORT PickerLinkMedia {
+  GURL url;
+
+  explicit PickerLinkMedia(GURL url);
+};
+
+// Rich media that can be inserted or copied, such as text and images.
+using PickerRichMedia =
+    std::variant<PickerTextMedia, PickerImageMedia, PickerLinkMedia>;
+
+}  // namespace ash
+
+#endif  // ASH_PICKER_PICKER_INSERT_MEDIA_REQUEST_H_
diff --git a/ash/picker/picker_search_controller.cc b/ash/picker/picker_search_controller.cc
index 84a1d86..8bac265 100644
--- a/ash/picker/picker_search_controller.cc
+++ b/ash/picker/picker_search_controller.cc
@@ -47,8 +47,8 @@
 constexpr int kMaxSymbolResults = 2;
 constexpr int kMaxEmoticonResults = 2;
 
-base::span<const std::string> FirstNOrLessElements(
-    base::span<const std::string> container,
+base::span<const emoji::EmojiSearchEntry> FirstNOrLessElements(
+    base::span<const emoji::EmojiSearchEntry> container,
     size_t n) {
   return container.subspan(0, std::min(container.size(), n));
 }
@@ -87,7 +87,7 @@
                                 category == PickerCategory::kOpenTabs)) {
     cros_search_start_ = base::TimeTicks::Now();
     client_->StartCrosSearch(
-        query,
+        query, category,
         base::BindRepeating(&PickerSearchController::HandleCrosSearchResults,
                             weak_ptr_factory_.GetWeakPtr()));
   }
@@ -179,6 +179,10 @@
     sections.emplace_back(PickerSectionType::kFiles,
                           std::move(local_file_results_));
   }
+  if (!drive_file_results_.empty()) {
+    sections.emplace_back(PickerSectionType::kDriveFiles,
+                          std::move(drive_file_results_));
+  }
   if (!gif_results_.empty()) {
     sections.push_back(PickerSearchResultsSection(PickerSectionType::kGifs,
                                                   std::move(gif_results_)));
@@ -230,6 +234,24 @@
             PickerSectionType::kLinks, std::move(omnibox_results_)));
       }
       break;
+    case AppListSearchResultType::kDriveSearch: {
+      if (cros_search_start_.has_value()) {
+        base::TimeDelta elapsed = base::TimeTicks::Now() - *cros_search_start_;
+        base::UmaHistogramTimes("Ash.Picker.Search.DriveProvider.QueryTime",
+                                elapsed);
+      }
+      drive_file_results_ = std::move(results);
+      size_t files_to_remove =
+          std::max<size_t>(drive_file_results_.size(), 3) - 3;
+      drive_file_results_.erase(drive_file_results_.end() - files_to_remove,
+                                drive_file_results_.end());
+
+      if (IsPostBurnIn()) {
+        AppendPostBurnInResults(PickerSearchResultsSection(
+            PickerSectionType::kDriveFiles, std::move(drive_file_results_)));
+      }
+      break;
+    }
     case AppListSearchResultType::kFileSearch: {
       if (cros_search_start_.has_value()) {
         base::TimeDelta elapsed = base::TimeTicks::Now() - *cros_search_start_;
@@ -289,20 +311,20 @@
   emoji_results_.reserve(kMaxEmojiResults + kMaxSymbolResults +
                          kMaxEmoticonResults);
 
-  for (const std::string& result :
+  for (const emoji::EmojiSearchEntry& result :
        FirstNOrLessElements(results.emojis, kMaxEmojiResults)) {
     emoji_results_.push_back(
-        PickerSearchResult::Emoji(base::UTF8ToUTF16(result)));
+        PickerSearchResult::Emoji(base::UTF8ToUTF16(result.emoji_string)));
   }
-  for (const std::string& result :
+  for (const emoji::EmojiSearchEntry& result :
        FirstNOrLessElements(results.symbols, kMaxSymbolResults)) {
     emoji_results_.push_back(
-        PickerSearchResult::Symbol(base::UTF8ToUTF16(result)));
+        PickerSearchResult::Symbol(base::UTF8ToUTF16(result.emoji_string)));
   }
-  for (const std::string& result :
+  for (const emoji::EmojiSearchEntry& result :
        FirstNOrLessElements(results.emoticons, kMaxEmoticonResults)) {
     emoji_results_.push_back(
-        PickerSearchResult::Emoticon(base::UTF8ToUTF16(result)));
+        PickerSearchResult::Emoticon(base::UTF8ToUTF16(result.emoji_string)));
   }
 }
 
diff --git a/ash/picker/picker_search_controller.h b/ash/picker/picker_search_controller.h
index d97dfbc..dd54f3e 100644
--- a/ash/picker/picker_search_controller.h
+++ b/ash/picker/picker_search_controller.h
@@ -94,6 +94,7 @@
   std::vector<PickerSearchResult> gif_results_;
   std::vector<PickerSearchResult> emoji_results_;
   std::vector<PickerSearchResult> local_file_results_;
+  std::vector<PickerSearchResult> drive_file_results_;
 
   PickerSearchDebouncer gif_search_debouncer_;
 
diff --git a/ash/picker/picker_search_controller_unittest.cc b/ash/picker/picker_search_controller_unittest.cc
index 8c8377a..841449b 100644
--- a/ash/picker/picker_search_controller_unittest.cc
+++ b/ash/picker/picker_search_controller_unittest.cc
@@ -79,7 +79,7 @@
     // Set default behaviours. These can be overridden with `WillOnce` and
     // `WillRepeatedly`.
     ON_CALL(*this, StartCrosSearch)
-        .WillByDefault(SaveArg<1>(cros_search_callback()));
+        .WillByDefault(SaveArg<2>(cros_search_callback()));
     ON_CALL(*this, FetchGifSearch)
         .WillByDefault(
             Invoke(this, &MockPickerClient::FetchGifSearchToSetCallback));
@@ -105,7 +105,9 @@
   MOCK_METHOD(void, StopGifSearch, (), (override));
   MOCK_METHOD(void,
               StartCrosSearch,
-              (const std::u16string& query, CrosSearchResultsCallback callback),
+              (const std::u16string& query,
+               std::optional<PickerCategory> category,
+               CrosSearchResultsCallback callback),
               (override));
   MOCK_METHOD(void, StopCrosQuery, (), (override));
 
@@ -167,7 +169,7 @@
   NiceMock<MockPickerClient> client;
   PickerSearchController controller(&client, kAllCategories, kBurnInPeriod);
   NiceMock<MockSearchResultsCallback> search_results_callback;
-  EXPECT_CALL(client, StartCrosSearch(Eq(u"cat"), _)).Times(1);
+  EXPECT_CALL(client, StartCrosSearch(Eq(u"cat"), _, _)).Times(1);
 
   controller.StartSearch(
       u"cat", std::nullopt,
@@ -252,6 +254,7 @@
   ON_CALL(client, StartCrosSearch)
       .WillByDefault([&search_started, &client](
                          const std::u16string& query,
+                         std::optional<PickerCategory> category,
                          PickerClient::CrosSearchResultsCallback callback) {
         client.StopCrosQuery();
         search_started = true;
@@ -360,6 +363,7 @@
       .Times(2)
       .WillRepeatedly([&search_started, &client](
                           const std::u16string& query,
+                          std::optional<PickerCategory> category,
                           PickerClient::CrosSearchResultsCallback callback) {
         client.StopCrosQuery();
         search_started = true;
@@ -379,7 +383,8 @@
   histogram.ExpectTotalCount("Ash.Picker.Search.OmniboxProvider.QueryTime", 0);
 }
 
-TEST_F(PickerSearchControllerTest, DoesNotRecordOmniboxMetricsIfFileResponse) {
+TEST_F(PickerSearchControllerTest,
+       DoesNotRecordOmniboxMetricsIfOtherCrosSearchResponse) {
   base::HistogramTester histogram;
   NiceMock<MockPickerClient> client;
   PickerSearchController controller(&client, kAllCategories, kBurnInPeriod);
@@ -398,6 +403,7 @@
       .Times(2)
       .WillRepeatedly([&search_started, &client](
                           const std::u16string& query,
+                          std::optional<PickerCategory> category,
                           PickerClient::CrosSearchResultsCallback callback) {
         client.StopCrosQuery();
         search_started = true;
@@ -504,6 +510,7 @@
       .Times(2)
       .WillRepeatedly([&search_started, &client](
                           const std::u16string& query,
+                          std::optional<PickerCategory> category,
                           PickerClient::CrosSearchResultsCallback callback) {
         client.StopCrosQuery();
         search_started = true;
@@ -523,7 +530,8 @@
   histogram.ExpectTotalCount("Ash.Picker.Search.FileProvider.QueryTime", 0);
 }
 
-TEST_F(PickerSearchControllerTest, DoesNotRecordFileMetricsIfOmniboxResponse) {
+TEST_F(PickerSearchControllerTest,
+       DoesNotRecordFileMetricsIfOtherCrosSearchResponse) {
   base::HistogramTester histogram;
   NiceMock<MockPickerClient> client;
   PickerSearchController controller(&client, kAllCategories, kBurnInPeriod);
@@ -542,6 +550,7 @@
       .Times(2)
       .WillRepeatedly([&search_started, &client](
                           const std::u16string& query,
+                          std::optional<PickerCategory> category,
                           PickerClient::CrosSearchResultsCallback callback) {
         client.StopCrosQuery();
         search_started = true;
@@ -566,6 +575,155 @@
   histogram.ExpectTotalCount("Ash.Picker.Search.FileProvider.QueryTime", 0);
 }
 
+TEST_F(PickerSearchControllerTest, ShowsResultsFromDriveSearch) {
+  NiceMock<MockPickerClient> client;
+  PickerSearchController controller(&client, kAllCategories, kBurnInPeriod);
+  MockSearchResultsCallback search_results_callback;
+  EXPECT_CALL(search_results_callback, Call).Times(AnyNumber());
+  EXPECT_CALL(search_results_callback,
+              Call(Contains(AllOf(
+                  Property("type", &PickerSearchResultsSection::type,
+                           PickerSectionType::kDriveFiles),
+                  Property("results", &PickerSearchResultsSection::results,
+                           ElementsAre(Property(
+                               "data", &PickerSearchResult::data,
+                               VariantWith<PickerSearchResult::TextData>(Field(
+                                   "text", &PickerSearchResult::TextData::text,
+                                   u"catrbug_135117.jpg")))))))))
+      .Times(AtLeast(1));
+
+  controller.StartSearch(
+      u"cat", std::nullopt,
+      base::BindRepeating(&MockSearchResultsCallback::Call,
+                          base::Unretained(&search_results_callback)));
+  client.cros_search_callback()->Run(
+      ash::AppListSearchResultType::kDriveSearch,
+      {ash::PickerSearchResult::Text(u"catrbug_135117.jpg")});
+  task_environment().FastForwardBy(kBurnInPeriod);
+}
+
+TEST_F(PickerSearchControllerTest, RecordsDriveMetricsBeforeBurnIn) {
+  base::HistogramTester histogram;
+  NiceMock<MockPickerClient> client;
+  PickerSearchController controller(&client, kAllCategories, kBurnInPeriod);
+  MockSearchResultsCallback search_results_callback;
+
+  controller.StartSearch(
+      u"cat", std::nullopt,
+      base::BindRepeating(&MockSearchResultsCallback::Call,
+                          base::Unretained(&search_results_callback)));
+  task_environment().FastForwardBy(kBeforeBurnIn);
+  client.cros_search_callback()->Run(
+      ash::AppListSearchResultType::kDriveSearch,
+      {ash::PickerSearchResult::Text(u"catrbug_135117.jpg")});
+
+  histogram.ExpectUniqueTimeSample("Ash.Picker.Search.DriveProvider.QueryTime",
+                                   kBeforeBurnIn, 1);
+}
+
+TEST_F(PickerSearchControllerTest, RecordsDriveMetricsAfterBurnIn) {
+  base::HistogramTester histogram;
+  NiceMock<MockPickerClient> client;
+  PickerSearchController controller(&client, kAllCategories, kBurnInPeriod);
+  MockSearchResultsCallback search_results_callback;
+
+  controller.StartSearch(
+      u"cat", std::nullopt,
+      base::BindRepeating(&MockSearchResultsCallback::Call,
+                          base::Unretained(&search_results_callback)));
+  task_environment().FastForwardBy(kAfterBurnIn);
+  client.cros_search_callback()->Run(
+      ash::AppListSearchResultType::kDriveSearch,
+      {ash::PickerSearchResult::Text(u"catrbug_135117.jpg")});
+
+  histogram.ExpectUniqueTimeSample("Ash.Picker.Search.DriveProvider.QueryTime",
+                                   kAfterBurnIn, 1);
+}
+
+TEST_F(PickerSearchControllerTest, DoesNotRecordDriveMetricsIfNoFileResponse) {
+  base::HistogramTester histogram;
+  NiceMock<MockPickerClient> client;
+  PickerSearchController controller(&client, kAllCategories, kBurnInPeriod);
+  MockSearchResultsCallback search_results_callback;
+  bool search_started = false;
+  EXPECT_CALL(client, StopCrosQuery)
+      .Times(AtLeast(2))
+      .WillRepeatedly([&search_started, &client]() {
+        if (search_started) {
+          client.cros_search_callback()->Run(AppListSearchResultType::kOmnibox,
+                                             {});
+        }
+        search_started = false;
+      });
+  EXPECT_CALL(client, StartCrosSearch)
+      .Times(2)
+      .WillRepeatedly([&search_started, &client](
+                          const std::u16string& query,
+                          std::optional<PickerCategory> category,
+                          PickerClient::CrosSearchResultsCallback callback) {
+        client.StopCrosQuery();
+        search_started = true;
+        *client.cros_search_callback() = std::move(callback);
+      });
+
+  controller.StartSearch(
+      u"cat", std::nullopt,
+      base::BindRepeating(&MockSearchResultsCallback::Call,
+                          base::Unretained(&search_results_callback)));
+  task_environment().FastForwardBy(kBeforeBurnIn);
+  controller.StartSearch(
+      u"dog", std::nullopt,
+      base::BindRepeating(&MockSearchResultsCallback::Call,
+                          base::Unretained(&search_results_callback)));
+
+  histogram.ExpectTotalCount("Ash.Picker.Search.DriveProvider.QueryTime", 0);
+}
+
+TEST_F(PickerSearchControllerTest,
+       DoesNotRecordDriveMetricsIfOtherCrosSearchResponse) {
+  base::HistogramTester histogram;
+  NiceMock<MockPickerClient> client;
+  PickerSearchController controller(&client, kAllCategories, kBurnInPeriod);
+  MockSearchResultsCallback search_results_callback;
+  bool search_started = false;
+  EXPECT_CALL(client, StopCrosQuery)
+      .Times(AtLeast(2))
+      .WillRepeatedly([&search_started, &client]() {
+        if (search_started) {
+          client.cros_search_callback()->Run(AppListSearchResultType::kOmnibox,
+                                             {});
+        }
+        search_started = false;
+      });
+  EXPECT_CALL(client, StartCrosSearch)
+      .Times(2)
+      .WillRepeatedly([&search_started, &client](
+                          const std::u16string& query,
+                          std::optional<PickerCategory> category,
+                          PickerClient::CrosSearchResultsCallback callback) {
+        client.StopCrosQuery();
+        search_started = true;
+        *client.cros_search_callback() = std::move(callback);
+      });
+
+  controller.StartSearch(
+      u"cat", std::nullopt,
+      base::BindRepeating(&MockSearchResultsCallback::Call,
+                          base::Unretained(&search_results_callback)));
+  task_environment().FastForwardBy(kBeforeBurnIn);
+  client.cros_search_callback()->Run(
+      ash::AppListSearchResultType::kOmnibox,
+      {ash::PickerSearchResult::BrowsingHistory(
+          GURL("https://www.google.com/search?q=cat"), u"cat - Google Search",
+          ui::ImageModel())});
+  controller.StartSearch(
+      u"dog", std::nullopt,
+      base::BindRepeating(&MockSearchResultsCallback::Call,
+                          base::Unretained(&search_results_callback)));
+
+  histogram.ExpectTotalCount("Ash.Picker.Search.DriveProvider.QueryTime", 0);
+}
+
 TEST_F(PickerSearchControllerTest, DoesNotSendQueryToGifSearchImmediately) {
   NiceMock<MockPickerClient> client;
   PickerSearchController controller(&client, kAllCategories, kBurnInPeriod);
@@ -606,9 +764,9 @@
               Contains(Property(
                   "data", &PickerSearchResult::data,
                   VariantWith<PickerSearchResult::GifData>(AllOf(
-                      Field("url", &PickerSearchResult::GifData::url,
+                      Field("full_url", &PickerSearchResult::GifData::full_url,
                             Property("spec", &GURL::spec,
-                                     "https://media.tenor.com/GOabrbLMl4AAAAAd/"
+                                     "https://media.tenor.com/GOabrbLMl4AAAAAC/"
                                      "plink-cat-plink.gif")),
                       Field("content_description",
                             &PickerSearchResult::GifData::content_description,
@@ -625,6 +783,8 @@
       .Run({ash::PickerSearchResult::Gif(
           GURL("https://media.tenor.com/GOabrbLMl4AAAAAd/plink-cat-plink.gif"),
           GURL("https://media.tenor.com/GOabrbLMl4AAAAAe/plink-cat-plink.png"),
+          gfx::Size(360, 360),
+          GURL("https://media.tenor.com/GOabrbLMl4AAAAAC/plink-cat-plink.gif"),
           gfx::Size(480, 480), u"cat blink")});
   task_environment().FastForwardBy(kBurnInPeriod -
                                    PickerSearchController::kGifDebouncingDelay);
@@ -646,9 +806,9 @@
               Contains(Property(
                   "data", &PickerSearchResult::data,
                   VariantWith<PickerSearchResult::GifData>(AllOf(
-                      Field("url", &PickerSearchResult::GifData::url,
+                      Field("full_url", &PickerSearchResult::GifData::full_url,
                             Property("spec", &GURL::spec,
-                                     "https://media.tenor.com/GOabrbLMl4AAAAAd/"
+                                     "https://media.tenor.com/GOabrbLMl4AAAAAC/"
                                      "plink-cat-plink.gif")),
                       Field("content_description",
                             &PickerSearchResult::GifData::content_description,
@@ -687,10 +847,9 @@
               Contains(Property(
                   "data", &PickerSearchResult::data,
                   VariantWith<PickerSearchResult::GifData>(AllOf(
-                      Field("url", &PickerSearchResult::GifData::url,
+                      Field("full_url", &PickerSearchResult::GifData::full_url,
                             Property("spec", &GURL::spec,
-                                     "https://media.tenor.com/"
-                                     "GOabrbLMl4AAAAAd/"
+                                     "https://media.tenor.com/GOabrbLMl4AAAAAC/"
                                      "plink-cat-plink.gif")),
                       Field("content_description",
                             &PickerSearchResult::GifData::content_description,
@@ -712,6 +871,8 @@
       .Run({ash::PickerSearchResult::Gif(
           GURL("https://media.tenor.com/GOabrbLMl4AAAAAd/plink-cat-plink.gif"),
           GURL("https://media.tenor.com/GOabrbLMl4AAAAAe/plink-cat-plink.png"),
+          gfx::Size(360, 360),
+          GURL("https://media.tenor.com/GOabrbLMl4AAAAAC/plink-cat-plink.gif"),
           gfx::Size(480, 480), u"cat blink")});
   task_environment().FastForwardBy(kBurnInPeriod -
                                    PickerSearchController::kGifDebouncingDelay);
@@ -732,6 +893,8 @@
       .Run({ash::PickerSearchResult::Gif(
           GURL("https://media.tenor.com/GOabrbLMl4AAAAAd/plink-cat-plink.gif"),
           GURL("https://media.tenor.com/GOabrbLMl4AAAAAe/plink-cat-plink.png"),
+          gfx::Size(360, 360),
+          GURL("https://media.tenor.com/GOabrbLMl4AAAAAC/plink-cat-plink.gif"),
           gfx::Size(480, 480), u"cat blink")});
 
   histogram.ExpectUniqueTimeSample(
@@ -754,6 +917,8 @@
       .Run({ash::PickerSearchResult::Gif(
           GURL("https://media.tenor.com/GOabrbLMl4AAAAAd/plink-cat-plink.gif"),
           GURL("https://media.tenor.com/GOabrbLMl4AAAAAe/plink-cat-plink.png"),
+          gfx::Size(360, 360),
+          GURL("https://media.tenor.com/GOabrbLMl4AAAAAC/plink-cat-plink.gif"),
           gfx::Size(480, 480), u"cat blink")});
 
   histogram.ExpectUniqueTimeSample(
@@ -796,10 +961,11 @@
                   Contains(Property(
                       "data", &PickerSearchResult::data,
                       VariantWith<PickerSearchResult::GifData>(AllOf(
-                          Field("url", &PickerSearchResult::GifData::url,
+                          Field("full_url",
+                                &PickerSearchResult::GifData::full_url,
                                 Property("spec", &GURL::spec,
                                          "https://media.tenor.com/"
-                                         "GOabrbLMl4AAAAAd/"
+                                         "GOabrbLMl4AAAAAC/"
                                          "plink-cat-plink.gif")),
                           Field(
                               "content_description",
@@ -838,6 +1004,8 @@
       .Run({ash::PickerSearchResult::Gif(
           GURL("https://media.tenor.com/GOabrbLMl4AAAAAd/plink-cat-plink.gif"),
           GURL("https://media.tenor.com/GOabrbLMl4AAAAAe/plink-cat-plink.png"),
+          gfx::Size(360, 360),
+          GURL("https://media.tenor.com/GOabrbLMl4AAAAAC/plink-cat-plink.gif"),
           gfx::Size(480, 480), u"cat blink")});
   task_environment().FastForwardBy(kBurnInPeriod -
                                    PickerSearchController::kGifDebouncingDelay);
@@ -866,6 +1034,8 @@
       .Run({ash::PickerSearchResult::Gif(
           GURL("https://media.tenor.com/GOabrbLMl4AAAAAd/plink-cat-plink.gif"),
           GURL("https://media.tenor.com/GOabrbLMl4AAAAAe/plink-cat-plink.png"),
+          gfx::Size(360, 360),
+          GURL("https://media.tenor.com/GOabrbLMl4AAAAAC/plink-cat-plink.gif"),
           gfx::Size(480, 480), u"cat blink")});
   task_environment().FastForwardBy(kBurnInPeriod);
 }
@@ -893,6 +1063,8 @@
       .Run({ash::PickerSearchResult::Gif(
           GURL("https://media.tenor.com/GOabrbLMl4AAAAAd/plink-cat-plink.gif"),
           GURL("https://media.tenor.com/GOabrbLMl4AAAAAe/plink-cat-plink.png"),
+          gfx::Size(360, 360),
+          GURL("https://media.tenor.com/GOabrbLMl4AAAAAC/plink-cat-plink.gif"),
           gfx::Size(480, 480), u"cat blink")});
 }
 
@@ -911,10 +1083,9 @@
               Contains(Property(
                   "data", &PickerSearchResult::data,
                   VariantWith<PickerSearchResult::GifData>(AllOf(
-                      Field("url", &PickerSearchResult::GifData::url,
+                      Field("full_url", &PickerSearchResult::GifData::full_url,
                             Property("spec", &GURL::spec,
-                                     "https://media.tenor.com/"
-                                     "GOabrbLMl4AAAAAd/"
+                                     "https://media.tenor.com/GOabrbLMl4AAAAAC/"
                                      "plink-cat-plink.gif")),
                       Field("content_description",
                             &PickerSearchResult::GifData::content_description,
@@ -930,21 +1101,29 @@
       .Run({ash::PickerSearchResult::Gif(
           GURL("https://media.tenor.com/GOabrbLMl4AAAAAd/plink-cat-plink.gif"),
           GURL("https://media.tenor.com/GOabrbLMl4AAAAAe/plink-cat-plink.png"),
+          gfx::Size(360, 360),
+          GURL("https://media.tenor.com/GOabrbLMl4AAAAAC/plink-cat-plink.gif"),
           gfx::Size(480, 480), u"cat blink")});
 }
 
 TEST_F(PickerSearchControllerTest, OnlyStartCrosSearchForCertainCategories) {
   NiceMock<MockPickerClient> client;
   PickerSearchController controller(&client, kAllCategories, kBurnInPeriod);
-  EXPECT_CALL(client, StartCrosSearch(Eq(u"ant"), _)).Times(1);
-  EXPECT_CALL(client, StartCrosSearch(Eq(u"bat"), _)).Times(1);
-  EXPECT_CALL(client, StartCrosSearch(Eq(u"cat"), _)).Times(1);
+  EXPECT_CALL(client,
+              StartCrosSearch(Eq(u"ant"), Eq(PickerCategory::kBookmarks), _))
+      .Times(1);
+  EXPECT_CALL(client, StartCrosSearch(Eq(u"bat"),
+                                      Eq(PickerCategory::kBrowsingHistory), _))
+      .Times(1);
+  EXPECT_CALL(client,
+              StartCrosSearch(Eq(u"cat"), Eq(PickerCategory::kOpenTabs), _))
+      .Times(1);
   EXPECT_CALL(client, FetchGifSearch(_, _)).Times(0);
 
-  controller.StartSearch(u"cat", PickerCategory::kBookmarks, base::DoNothing());
-  controller.StartSearch(u"ant", PickerCategory::kBrowsingHistory,
+  controller.StartSearch(u"ant", PickerCategory::kBookmarks, base::DoNothing());
+  controller.StartSearch(u"bat", PickerCategory::kBrowsingHistory,
                          base::DoNothing());
-  controller.StartSearch(u"bat", PickerCategory::kOpenTabs, base::DoNothing());
+  controller.StartSearch(u"cat", PickerCategory::kOpenTabs, base::DoNothing());
 }
 
 }  // namespace
diff --git a/ash/picker/picker_test_util.cc b/ash/picker/picker_test_util.cc
index 6aa41fc2..c3c5077 100644
--- a/ash/picker/picker_test_util.cc
+++ b/ash/picker/picker_test_util.cc
@@ -14,6 +14,13 @@
 
 namespace ash {
 
+std::u16string ReadTextFromClipboard(ui::Clipboard* clipboard) {
+  std::u16string data;
+
+  clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste, nullptr, &data);
+  return data;
+}
+
 std::u16string ReadHtmlFromClipboard(ui::Clipboard* clipboard) {
   std::u16string data;
   std::string url;
diff --git a/ash/picker/picker_test_util.h b/ash/picker/picker_test_util.h
index 01267f5..977ac0f 100644
--- a/ash/picker/picker_test_util.h
+++ b/ash/picker/picker_test_util.h
@@ -22,6 +22,9 @@
 
 namespace ash {
 
+// Returns the text contents of `clipboard`.
+ASH_EXPORT std::u16string ReadTextFromClipboard(ui::Clipboard* clipboard);
+
 // Returns the HTML contents of `clipboard`.
 ASH_EXPORT std::u16string ReadHtmlFromClipboard(ui::Clipboard* clipboard);
 
diff --git a/ash/picker/search/picker_category_search.cc b/ash/picker/search/picker_category_search.cc
index 784399d..242b283 100644
--- a/ash/picker/search/picker_category_search.cc
+++ b/ash/picker/search/picker_category_search.cc
@@ -4,6 +4,7 @@
 
 #include "ash/picker/search/picker_category_search.h"
 
+#include <string>
 #include <string_view>
 #include <vector>
 
@@ -11,29 +12,26 @@
 #include "ash/public/cpp/picker/picker_category.h"
 #include "ash/public/cpp/picker/picker_search_result.h"
 #include "base/check.h"
-#include "base/ranges/algorithm.h"
-#include "base/strings/string_util.h"
+#include "chromeos/ash/components/string_matching/prefix_matcher.h"
+#include "chromeos/ash/components/string_matching/tokenized_string.h"
 
 namespace ash {
-namespace {
-
-bool ContainsCaseInsensitive(std::u16string_view haystack,
-                             std::u16string_view needle) {
-  return base::ranges::search(haystack, needle,
-                              base::CaseInsensitiveCompareASCII<char>()) !=
-         haystack.end();
-}
-
-}  // namespace
 
 std::vector<PickerSearchResult> PickerCategorySearch(
     base::span<const PickerCategory> categories,
     std::u16string_view query) {
   CHECK(!query.empty());
+  string_matching::TokenizedString tokenized_query((std::u16string(query)));
 
   std::vector<PickerSearchResult> matches;
   for (const PickerCategory category : categories) {
-    if (ContainsCaseInsensitive(GetLabelForPickerCategory(category), query)) {
+    string_matching::TokenizedString tokenized_category(
+        GetLabelForPickerCategory(category));
+    // Both arguments are stored as `raw_ref`s in the `PrefixMatcher` below, so
+    // they need to outlive the matcher.
+    string_matching::PrefixMatcher matcher(tokenized_query, tokenized_category);
+    // TODO: b/325973235 - Use `matcher.relevance()` to sort these results.
+    if (matcher.Match()) {
       matches.push_back(PickerSearchResult::Category(category));
     }
   }
diff --git a/ash/picker/search/picker_category_search_unittest.cc b/ash/picker/search/picker_category_search_unittest.cc
index 9fe3d49..3f4de066 100644
--- a/ash/picker/search/picker_category_search_unittest.cc
+++ b/ash/picker/search/picker_category_search_unittest.cc
@@ -68,11 +68,17 @@
             .query = u"e",
             .expected_categories = {PickerCategory::kEmojis},
         },
+        // Prefix match in second word
+        TestCase{
+            .available_categories = {PickerCategory::kOpenTabs},
+            .query = u"ta",
+            .expected_categories = {PickerCategory::kOpenTabs},
+        },
         // Substring match
         TestCase{
             .available_categories = {PickerCategory::kEmojis},
             .query = u"moj",
-            .expected_categories = {PickerCategory::kEmojis},
+            .expected_categories = {},
         },
         // Category unavailable
         TestCase{
diff --git a/ash/picker/views/picker_category_view.cc b/ash/picker/views/picker_category_view.cc
index c8bd01b..a0a7c96 100644
--- a/ash/picker/views/picker_category_view.cc
+++ b/ash/picker/views/picker_category_view.cc
@@ -31,8 +31,24 @@
 
 PickerCategoryView::~PickerCategoryView() = default;
 
-bool PickerCategoryView::OnEnterKeyPressed() {
-  return search_results_view_->OnEnterKeyPressed();
+bool PickerCategoryView::DoPseudoFocusedAction() {
+  return search_results_view_->DoPseudoFocusedAction();
+}
+
+bool PickerCategoryView::MovePseudoFocusUp() {
+  return search_results_view_->MovePseudoFocusUp();
+}
+
+bool PickerCategoryView::MovePseudoFocusDown() {
+  return search_results_view_->MovePseudoFocusDown();
+}
+
+bool PickerCategoryView::MovePseudoFocusLeft() {
+  return search_results_view_->MovePseudoFocusLeft();
+}
+
+bool PickerCategoryView::MovePseudoFocusRight() {
+  return search_results_view_->MovePseudoFocusRight();
 }
 
 void PickerCategoryView::SetResults(
diff --git a/ash/picker/views/picker_category_view.h b/ash/picker/views/picker_category_view.h
index 26345a8..c1fcfeb 100644
--- a/ash/picker/views/picker_category_view.h
+++ b/ash/picker/views/picker_category_view.h
@@ -30,7 +30,11 @@
   ~PickerCategoryView() override;
 
   // PickerPageView:
-  bool OnEnterKeyPressed() override;
+  bool DoPseudoFocusedAction() override;
+  bool MovePseudoFocusUp() override;
+  bool MovePseudoFocusDown() override;
+  bool MovePseudoFocusLeft() override;
+  bool MovePseudoFocusRight() override;
 
   // Replaces the current results with `sections`.
   void SetResults(std::vector<PickerSearchResultsSection> sections);
diff --git a/ash/picker/views/picker_emoji_item_view.cc b/ash/picker/views/picker_emoji_item_view.cc
index 24114cc..658340d 100644
--- a/ash/picker/views/picker_emoji_item_view.cc
+++ b/ash/picker/views/picker_emoji_item_view.cc
@@ -9,11 +9,9 @@
 
 #include "ash/ash_element_identifiers.h"
 #include "ash/picker/views/picker_item_view.h"
-#include "ash/style/style_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/chromeos/styles/cros_tokens_color_mappings.h"
 #include "ui/gfx/font_list.h"
-#include "ui/gfx/geometry/rounded_corners_f.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/view_class_properties.h"
 
@@ -26,7 +24,7 @@
                                      kPickerEmojiFontSize,
                                      gfx::Font::Weight::NORMAL);
 
-constexpr auto kPickerEmojiItemCornerRadius = gfx::RoundedCornersF(4);
+constexpr int kPickerEmojiItemCornerRadius = 4;
 
 }  // namespace
 
@@ -35,6 +33,7 @@
     const std::u16string& emoji)
     : PickerItemView(std::move(select_item_callback)) {
   SetUseDefaultFillLayout(true);
+  SetCornerRadius(kPickerEmojiItemCornerRadius);
   SetProperty(views::kElementIdentifierKey,
               kPickerSearchResultsEmojiItemElementId);
 
@@ -43,9 +42,6 @@
                                   .SetFontList(kPickerEmojiFont)
                                   .Build());
   SetAccessibleName(emoji_label_);
-
-  StyleUtil::InstallRoundedCornerHighlightPathGenerator(
-      this, kPickerEmojiItemCornerRadius);
 }
 
 std::u16string_view PickerEmojiItemView::GetTextForTesting() const {
diff --git a/ash/picker/views/picker_emoticon_item_view.cc b/ash/picker/views/picker_emoticon_item_view.cc
index 32c03a3..06d1d8a7 100644
--- a/ash/picker/views/picker_emoticon_item_view.cc
+++ b/ash/picker/views/picker_emoticon_item_view.cc
@@ -8,12 +8,10 @@
 #include <utility>
 
 #include "ash/picker/views/picker_item_view.h"
-#include "ash/style/style_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/chromeos/styles/cros_tokens_color_mappings.h"
 #include "ui/gfx/font_list.h"
 #include "ui/gfx/geometry/insets.h"
-#include "ui/gfx/geometry/rounded_corners_f.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/label.h"
 
@@ -28,7 +26,7 @@
 
 constexpr auto kPickerEmoticonItemMargins = gfx::Insets::VH(0, 6);
 
-constexpr auto kPickerEmoticonItemCornerRadius = gfx::RoundedCornersF(4);
+constexpr int kPickerEmoticonItemCornerRadius = 4;
 
 }  // namespace
 
@@ -37,6 +35,7 @@
     const std::u16string& emoticon)
     : PickerItemView(std::move(select_item_callback)) {
   SetUseDefaultFillLayout(true);
+  SetCornerRadius(kPickerEmoticonItemCornerRadius);
 
   emoticon_label_ = AddChildView(
       views::Builder<views::Label>()
@@ -46,9 +45,6 @@
           .SetBorder(views::CreateEmptyBorder(kPickerEmoticonItemMargins))
           .Build());
   SetAccessibleName(emoticon_label_);
-
-  StyleUtil::InstallRoundedCornerHighlightPathGenerator(
-      this, kPickerEmoticonItemCornerRadius);
 }
 
 PickerEmoticonItemView::~PickerEmoticonItemView() = default;
diff --git a/ash/picker/views/picker_focus_indicator.cc b/ash/picker/views/picker_focus_indicator.cc
new file mode 100644
index 0000000..34cca1eb7
--- /dev/null
+++ b/ash/picker/views/picker_focus_indicator.cc
@@ -0,0 +1,53 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/picker/views/picker_focus_indicator.h"
+
+#include "cc/paint/paint_flags.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkPath.h"
+#include "third_party/skia/include/core/SkScalar.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/skia_conversions.h"
+
+namespace ash {
+namespace {
+
+constexpr int kPickerFocusIndicatorWidth = 3;
+
+constexpr SkScalar kPickerFocusIndicatorRadius =
+    SkIntToScalar(kPickerFocusIndicatorWidth);
+constexpr SkScalar kPickerFocusIndicatorRadii[8] = {
+    0,
+    0,  // top-left
+    kPickerFocusIndicatorRadius,
+    kPickerFocusIndicatorRadius,  // top-right
+    kPickerFocusIndicatorRadius,
+    kPickerFocusIndicatorRadius,  // bottom-right
+    0,
+    0};  // bottom-left
+
+}  // namespace
+
+void PaintPickerFocusIndicator(gfx::Canvas* canvas,
+                               const gfx::Point& origin,
+                               int height,
+                               SkColor color) {
+  SkPath path;
+  const gfx::Rect focus_indicator_bounds(
+      origin, gfx::Size(kPickerFocusIndicatorWidth, height));
+  path.addRoundRect(gfx::RectToSkRect(focus_indicator_bounds),
+                    kPickerFocusIndicatorRadii);
+
+  cc::PaintFlags flags;
+  flags.setStyle(cc::PaintFlags::kFill_Style);
+  flags.setAntiAlias(true);
+  flags.setColor(color);
+  canvas->DrawPath(path, flags);
+}
+
+}  // namespace ash
diff --git a/ash/picker/views/picker_focus_indicator.h b/ash/picker/views/picker_focus_indicator.h
new file mode 100644
index 0000000..a6ebd47
--- /dev/null
+++ b/ash/picker/views/picker_focus_indicator.h
@@ -0,0 +1,26 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_PICKER_VIEWS_PICKER_FOCUS_INDICATOR_H_
+#define ASH_PICKER_VIEWS_PICKER_FOCUS_INDICATOR_H_
+
+#include "third_party/skia/include/core/SkColor.h"
+
+namespace gfx {
+class Canvas;
+class Point;
+}  // namespace gfx
+
+namespace ash {
+
+// Paints a focus indicator onto `canvas`. The painted indicator looks like a
+// vertical bar with half-rounded edges.
+void PaintPickerFocusIndicator(gfx::Canvas* canvas,
+                               const gfx::Point& origin,
+                               int height,
+                               SkColor color);
+
+}  // namespace ash
+
+#endif  // ASH_PICKER_VIEWS_PICKER_FOCUS_INDICATOR_H_
diff --git a/ash/picker/views/picker_image_item_grid_view.cc b/ash/picker/views/picker_image_item_grid_view.cc
index 58bd947..fde0372d 100644
--- a/ash/picker/views/picker_image_item_grid_view.cc
+++ b/ash/picker/views/picker_image_item_grid_view.cc
@@ -4,6 +4,7 @@
 
 #include "ash/picker/views/picker_image_item_grid_view.h"
 
+#include <iterator>
 #include <memory>
 #include <utility>
 
@@ -17,6 +18,7 @@
 #include "ui/views/layout/table_layout.h"
 #include "ui/views/view.h"
 #include "ui/views/view_class_properties.h"
+#include "ui/views/view_utils.h"
 
 namespace ash {
 namespace {
@@ -42,6 +44,17 @@
   return column;
 }
 
+PickerItemView* ItemInColumnWithIndexClosestTo(views::View* column,
+                                               const size_t index) {
+  if (column->children().empty()) {
+    return nullptr;
+  } else if (index < column->children().size()) {
+    return views::AsViewClass<PickerItemView>(column->children()[index].get());
+  } else {
+    return views::AsViewClass<PickerItemView>(column->children().back().get());
+  }
+}
+
 }  // namespace
 
 PickerImageItemGridView::PickerImageItemGridView(int grid_width)
@@ -71,6 +84,72 @@
 
 PickerImageItemGridView::~PickerImageItemGridView() = default;
 
+PickerItemView* PickerImageItemGridView::GetTopItem() {
+  views::View* column = children().front();
+  return column->children().empty() ? nullptr
+                                    : views::AsViewClass<PickerItemView>(
+                                          column->children().front().get());
+}
+
+PickerItemView* PickerImageItemGridView::GetBottomItem() {
+  views::View* tallest_column =
+      base::ranges::max(children(),
+                        /*comp=*/base::ranges::less(),
+                        /*proj=*/[](const views::View* v) {
+                          return v->GetPreferredSize().height();
+                        });
+  return tallest_column->children().empty()
+             ? nullptr
+             : views::AsViewClass<PickerItemView>(
+                   tallest_column->children().back().get());
+}
+
+PickerItemView* PickerImageItemGridView::GetItemAbove(PickerItemView* item) {
+  views::View* column = GetColumnContaining(item);
+  if (!column || item == column->children().front()) {
+    return nullptr;
+  }
+  return views::AsViewClass<PickerItemView>(
+      std::prev(base::ranges::find(column->children(), item))->get());
+}
+
+PickerItemView* PickerImageItemGridView::GetItemBelow(PickerItemView* item) {
+  views::View* column = GetColumnContaining(item);
+  if (!column || item == column->children().back()) {
+    return nullptr;
+  }
+  return views::AsViewClass<PickerItemView>(
+      std::next(base::ranges::find(column->children(), item))->get());
+}
+
+PickerItemView* PickerImageItemGridView::GetItemLeftOf(PickerItemView* item) {
+  views::View* column = GetColumnContaining(item);
+  if (!column || column == children().front()) {
+    return nullptr;
+  }
+  // Prefer to return the item with the same index in the column to the left,
+  // since this will probably be at a similar height to `item` (at least in
+  // usual scenarios where the grid items all have similar dimensions).
+  const size_t item_index = column->GetIndexOf(item).value();
+  views::View* left_column =
+      std::prev(base::ranges::find(children(), column))->get();
+  return ItemInColumnWithIndexClosestTo(left_column, item_index);
+}
+
+PickerItemView* PickerImageItemGridView::GetItemRightOf(PickerItemView* item) {
+  views::View* column = GetColumnContaining(item);
+  if (!column || column == children().back()) {
+    return nullptr;
+  }
+  // Prefer to return the item with the same index in the column to the right,
+  // since this will probably be at a similar height to `item` (at least in
+  // usual scenarios where the grid items all have similar dimensions).
+  const size_t item_index = column->GetIndexOf(item).value();
+  views::View* right_column =
+      std::next(base::ranges::find(children(), column))->get();
+  return ItemInColumnWithIndexClosestTo(right_column, item_index);
+}
+
 PickerImageItemView* PickerImageItemGridView::AddImageItem(
     std::unique_ptr<PickerImageItemView> image_item) {
   image_item->SetImageSizeFromWidth(GetImageGridColumnWidth(grid_width_));
@@ -83,6 +162,12 @@
   return shortest_column->AddChildView(std::move(image_item));
 }
 
+views::View* PickerImageItemGridView::GetColumnContaining(
+    PickerItemView* item) {
+  views::View* column = item->parent();
+  return column && column->parent() == this ? column : nullptr;
+}
+
 BEGIN_METADATA(PickerImageItemGridView)
 END_METADATA
 
diff --git a/ash/picker/views/picker_image_item_grid_view.h b/ash/picker/views/picker_image_item_grid_view.h
index d4321fe..bcaf5691 100644
--- a/ash/picker/views/picker_image_item_grid_view.h
+++ b/ash/picker/views/picker_image_item_grid_view.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "ash/ash_export.h"
+#include "ash/picker/views/picker_traversable_item_container.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/views/view.h"
 
@@ -17,7 +18,9 @@
 
 // Container view for the image items in a section. The image items are
 // displayed in a grid with two columns.
-class ASH_EXPORT PickerImageItemGridView : public views::View {
+class ASH_EXPORT PickerImageItemGridView
+    : public views::View,
+      public PickerTraversableItemContainer {
   METADATA_HEADER(PickerImageItemGridView, views::View)
 
  public:
@@ -26,10 +29,22 @@
   PickerImageItemGridView& operator=(const PickerImageItemGridView&) = delete;
   ~PickerImageItemGridView() override;
 
+  // PickerTraversableItemContainer:
+  PickerItemView* GetTopItem() override;
+  PickerItemView* GetBottomItem() override;
+  PickerItemView* GetItemAbove(PickerItemView* item) override;
+  PickerItemView* GetItemBelow(PickerItemView* item) override;
+  PickerItemView* GetItemLeftOf(PickerItemView* item) override;
+  PickerItemView* GetItemRightOf(PickerItemView* item) override;
+
   PickerImageItemView* AddImageItem(
       std::unique_ptr<PickerImageItemView> image_item);
 
  private:
+  // Returns the column containing `item`, or nullptr if `item` is not part of
+  // this grid.
+  views::View* GetColumnContaining(PickerItemView* item);
+
   int grid_width_ = 0;
 };
 
diff --git a/ash/picker/views/picker_image_item_grid_view_unittest.cc b/ash/picker/views/picker_image_item_grid_view_unittest.cc
index f1eb10a..6d566c3 100644
--- a/ash/picker/views/picker_image_item_grid_view_unittest.cc
+++ b/ash/picker/views/picker_image_item_grid_view_unittest.cc
@@ -19,10 +19,10 @@
 namespace ash {
 namespace {
 
-using ::testing::Eq;
+using ::testing::ElementsAre;
+using ::testing::IsEmpty;
 using ::testing::Pointee;
 using ::testing::Property;
-using ::testing::SizeIs;
 
 constexpr int kDefaultGridWidth = 320;
 
@@ -41,74 +41,268 @@
 }
 
 TEST(PickerImageItemGridViewTest, OneGifItem) {
-  PickerImageItemGridView image_item_grid(kDefaultGridWidth);
+  PickerImageItemGridView item_grid(kDefaultGridWidth);
 
-  image_item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 100)));
+  const PickerItemView* item =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 100)));
 
   // Two columns, one item in the first column.
   EXPECT_THAT(
-      image_item_grid.children(),
-      ElementsAre(Pointee(Property(&views::View::children, SizeIs(1))),
-                  Pointee(Property(&views::View::children, SizeIs(0)))));
+      item_grid.children(),
+      ElementsAre(Pointee(Property(&views::View::children, ElementsAre(item))),
+                  Pointee(Property(&views::View::children, IsEmpty()))));
 }
 
 TEST(PickerImageItemGridViewTest, TwoGifItems) {
-  PickerImageItemGridView image_item_grid(kDefaultGridWidth);
+  PickerImageItemGridView item_grid(kDefaultGridWidth);
 
-  image_item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 100)));
-  image_item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 100)));
+  const PickerItemView* item1 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 100)));
+  const PickerItemView* item2 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 100)));
 
   // Two columns, one item in each column.
   EXPECT_THAT(
-      image_item_grid.children(),
-      ElementsAre(Pointee(Property(&views::View::children, SizeIs(1))),
-                  Pointee(Property(&views::View::children, SizeIs(1)))));
+      item_grid.children(),
+      ElementsAre(
+          Pointee(Property(&views::View::children, ElementsAre(item1))),
+          Pointee(Property(&views::View::children, ElementsAre(item2)))));
 }
 
 TEST(PickerImageItemGridViewTest, GifItemsWithVaryingHeight) {
-  PickerImageItemGridView image_item_grid(kDefaultGridWidth);
+  PickerImageItemGridView item_grid(kDefaultGridWidth);
 
-  image_item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 120)));
-  image_item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 20)));
-  image_item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 30)));
-  image_item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 20)));
+  const PickerItemView* item1 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 120)));
+  const PickerItemView* item2 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 20)));
+  const PickerItemView* item3 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 30)));
+  const PickerItemView* item4 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 20)));
 
   // One item in first column, three items in second column.
   EXPECT_THAT(
-      image_item_grid.children(),
-      ElementsAre(Pointee(Property(&views::View::children, SizeIs(1))),
-                  Pointee(Property(&views::View::children, SizeIs(3)))));
+      item_grid.children(),
+      ElementsAre(Pointee(Property(&views::View::children, ElementsAre(item1))),
+                  Pointee(Property(&views::View::children,
+                                   ElementsAre(item2, item3, item4)))));
 }
 
 TEST(PickerImageItemGridViewTest, GifItemsAreResizedToSameWidth) {
-  PickerImageItemGridView image_item_grid(kDefaultGridWidth);
+  PickerImageItemGridView item_grid(kDefaultGridWidth);
 
-  image_item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 100)));
-  image_item_grid.AddImageItem(CreateGifItem(gfx::Size(80, 160)));
+  const PickerItemView* item1 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 100)));
+  const PickerItemView* item2 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(80, 160)));
 
-  const views::View::Views& columns = image_item_grid.children();
-  ASSERT_THAT(
-      columns,
-      ElementsAre(Pointee(Property(&views::View::children, SizeIs(1))),
-                  Pointee(Property(&views::View::children, SizeIs(1)))));
-  EXPECT_EQ(columns[0]->children()[0]->GetPreferredSize().width(),
-            columns[1]->children()[0]->GetPreferredSize().width());
+  EXPECT_EQ(item1->GetPreferredSize().width(),
+            item2->GetPreferredSize().width());
 }
 
 TEST(PickerImageItemGridViewTest, PreservesAspectRatioOfGifItems) {
-  PickerImageItemGridView image_item_grid(kDefaultGridWidth);
+  PickerImageItemGridView item_grid(kDefaultGridWidth);
 
   constexpr gfx::Size kGifDimensions(100, 200);
-  image_item_grid.AddImageItem(CreateGifItem(kGifDimensions));
+  const PickerItemView* item =
+      item_grid.AddImageItem(CreateGifItem(kGifDimensions));
 
-  const views::View::Views& columns = image_item_grid.children();
-  ASSERT_THAT(
-      columns,
-      ElementsAre(Pointee(Property(&views::View::children, SizeIs(1))),
-                  Pointee(Property(&views::View::children, SizeIs(0)))));
-  EXPECT_EQ(GetAspectRatio(columns[0]->children()[0]->GetPreferredSize()),
+  EXPECT_EQ(GetAspectRatio(item->GetPreferredSize()),
             GetAspectRatio(kGifDimensions));
 }
 
+TEST(PickerImageItemGridViewTest, GetsTopItem) {
+  PickerImageItemGridView item_grid(kDefaultGridWidth);
+
+  PickerItemView* item1 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 100)));
+  PickerItemView* item2 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 110)));
+  PickerItemView* item3 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 120)));
+
+  EXPECT_THAT(
+      item_grid.children(),
+      ElementsAre(
+          Pointee(Property(&views::View::children, ElementsAre(item1, item3))),
+          Pointee(Property(&views::View::children, ElementsAre(item2)))));
+  EXPECT_EQ(item_grid.GetTopItem(), item1);
+}
+
+TEST(PickerImageItemGridViewTest, EmptyGridHasNoTopItem) {
+  PickerImageItemGridView item_grid(kDefaultGridWidth);
+
+  EXPECT_EQ(item_grid.GetTopItem(), nullptr);
+}
+
+TEST(PickerImageItemGridViewTest, GetsBottomItem) {
+  PickerImageItemGridView item_grid(kDefaultGridWidth);
+
+  PickerItemView* item1 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 100)));
+  PickerItemView* item2 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 110)));
+  PickerItemView* item3 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 120)));
+
+  EXPECT_THAT(
+      item_grid.children(),
+      ElementsAre(
+          Pointee(Property(&views::View::children, ElementsAre(item1, item3))),
+          Pointee(Property(&views::View::children, ElementsAre(item2)))));
+  EXPECT_EQ(item_grid.GetBottomItem(), item3);
+}
+
+TEST(PickerImageItemGridViewTest, EmptyGridHasNoBottomItem) {
+  PickerImageItemGridView item_grid(kDefaultGridWidth);
+
+  EXPECT_EQ(item_grid.GetBottomItem(), nullptr);
+}
+
+TEST(PickerImageItemGridViewTest, GetsItemAbove) {
+  PickerImageItemGridView item_grid(kDefaultGridWidth);
+
+  PickerItemView* item1 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 100)));
+  PickerItemView* item2 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 110)));
+  PickerItemView* item3 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 120)));
+  PickerItemView* item4 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 130)));
+
+  EXPECT_THAT(item_grid.children(),
+              ElementsAre(Pointee(Property(&views::View::children,
+                                           ElementsAre(item1, item3))),
+                          Pointee(Property(&views::View::children,
+                                           ElementsAre(item2, item4)))));
+  EXPECT_EQ(item_grid.GetItemAbove(item1), nullptr);
+  EXPECT_EQ(item_grid.GetItemAbove(item2), nullptr);
+  EXPECT_EQ(item_grid.GetItemAbove(item3), item1);
+  EXPECT_EQ(item_grid.GetItemAbove(item4), item2);
+}
+
+TEST(PickerImageItemGridViewTest, ItemNotInGridHasNoItemAbove) {
+  PickerImageItemGridView item_grid(kDefaultGridWidth);
+  std::unique_ptr<PickerImageItemView> item_not_in_grid =
+      CreateGifItem(gfx::Size(100, 100));
+
+  EXPECT_EQ(item_grid.GetItemAbove(item_not_in_grid.get()), nullptr);
+}
+
+TEST(PickerImageItemGridViewTest, GetsItemBelow) {
+  PickerImageItemGridView item_grid(kDefaultGridWidth);
+
+  PickerItemView* item1 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 100)));
+  PickerItemView* item2 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 110)));
+  PickerItemView* item3 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 120)));
+  PickerItemView* item4 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 130)));
+
+  EXPECT_THAT(item_grid.children(),
+              ElementsAre(Pointee(Property(&views::View::children,
+                                           ElementsAre(item1, item3))),
+                          Pointee(Property(&views::View::children,
+                                           ElementsAre(item2, item4)))));
+  EXPECT_EQ(item_grid.GetItemBelow(item1), item3);
+  EXPECT_EQ(item_grid.GetItemBelow(item2), item4);
+  EXPECT_EQ(item_grid.GetItemBelow(item3), nullptr);
+  EXPECT_EQ(item_grid.GetItemBelow(item4), nullptr);
+}
+
+TEST(PickerImageItemGridViewTest, ItemNotInGridHasNoItemBelow) {
+  PickerImageItemGridView item_grid(kDefaultGridWidth);
+  std::unique_ptr<PickerImageItemView> item_not_in_grid =
+      CreateGifItem(gfx::Size(100, 100));
+
+  EXPECT_EQ(item_grid.GetItemBelow(item_not_in_grid.get()), nullptr);
+}
+
+TEST(PickerImageItemGridViewTest, GetsItemLeftOf) {
+  PickerImageItemGridView item_grid(kDefaultGridWidth);
+
+  PickerItemView* item1 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 100)));
+  PickerItemView* item2 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 110)));
+  PickerItemView* item3 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 120)));
+  PickerItemView* item4 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 130)));
+
+  EXPECT_THAT(item_grid.children(),
+              ElementsAre(Pointee(Property(&views::View::children,
+                                           ElementsAre(item1, item3))),
+                          Pointee(Property(&views::View::children,
+                                           ElementsAre(item2, item4)))));
+  EXPECT_EQ(item_grid.GetItemLeftOf(item1), nullptr);
+  EXPECT_EQ(item_grid.GetItemLeftOf(item2), item1);
+  EXPECT_EQ(item_grid.GetItemLeftOf(item3), nullptr);
+  EXPECT_EQ(item_grid.GetItemLeftOf(item4), item3);
+}
+
+TEST(PickerImageItemGridViewTest, GetsItemLeftOfWithUnbalancedColumns) {
+  PickerImageItemGridView item_grid(kDefaultGridWidth);
+
+  PickerItemView* item1 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 300)));
+  PickerItemView* item2 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 110)));
+  PickerItemView* item3 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 120)));
+
+  EXPECT_THAT(
+      item_grid.children(),
+      ElementsAre(Pointee(Property(&views::View::children, ElementsAre(item1))),
+                  Pointee(Property(&views::View::children,
+                                   ElementsAre(item2, item3)))));
+  EXPECT_EQ(item_grid.GetItemLeftOf(item1), nullptr);
+  EXPECT_EQ(item_grid.GetItemLeftOf(item2), item1);
+  EXPECT_EQ(item_grid.GetItemLeftOf(item3), item1);
+}
+
+TEST(PickerImageItemGridViewTest, ItemNotInGridHasNoItemLeftOf) {
+  PickerImageItemGridView item_grid(kDefaultGridWidth);
+  std::unique_ptr<PickerImageItemView> item_not_in_grid =
+      CreateGifItem(gfx::Size(100, 100));
+
+  EXPECT_EQ(item_grid.GetItemLeftOf(item_not_in_grid.get()), nullptr);
+}
+
+TEST(PickerImageItemGridViewTest, GetsItemRightOf) {
+  PickerImageItemGridView item_grid(kDefaultGridWidth);
+
+  PickerItemView* item1 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 100)));
+  PickerItemView* item2 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 110)));
+  PickerItemView* item3 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 120)));
+  PickerItemView* item4 =
+      item_grid.AddImageItem(CreateGifItem(gfx::Size(100, 130)));
+
+  EXPECT_THAT(item_grid.children(),
+              ElementsAre(Pointee(Property(&views::View::children,
+                                           ElementsAre(item1, item3))),
+                          Pointee(Property(&views::View::children,
+                                           ElementsAre(item2, item4)))));
+  EXPECT_EQ(item_grid.GetItemRightOf(item1), item2);
+  EXPECT_EQ(item_grid.GetItemRightOf(item2), nullptr);
+  EXPECT_EQ(item_grid.GetItemRightOf(item3), item4);
+  EXPECT_EQ(item_grid.GetItemRightOf(item4), nullptr);
+}
+
+TEST(PickerImageItemGridViewTest, ItemNotInGridHasNoItemRightOf) {
+  PickerImageItemGridView item_grid(kDefaultGridWidth);
+  std::unique_ptr<PickerImageItemView> item_not_in_grid =
+      CreateGifItem(gfx::Size(100, 100));
+
+  EXPECT_EQ(item_grid.GetItemRightOf(item_not_in_grid.get()), nullptr);
+}
+
 }  // namespace
 }  // namespace ash
diff --git a/ash/picker/views/picker_image_item_view.cc b/ash/picker/views/picker_image_item_view.cc
index 7f28645..07d0fa15 100644
--- a/ash/picker/views/picker_image_item_view.cc
+++ b/ash/picker/views/picker_image_item_view.cc
@@ -8,17 +8,15 @@
 #include <utility>
 
 #include "ash/picker/views/picker_item_view.h"
-#include "ash/style/style_util.h"
 #include "base/memory/raw_ptr.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
-#include "ui/gfx/geometry/rounded_corners_f.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/views/controls/image_view.h"
 
 namespace ash {
 namespace {
 
-constexpr auto kPickerImageItemCornerRadius = gfx::RoundedCornersF(8);
+constexpr int kPickerImageItemCornerRadius = 8;
 
 }  // namespace
 
@@ -27,13 +25,11 @@
     std::unique_ptr<views::ImageView> image)
     : PickerItemView(std::move(select_item_callback)) {
   SetUseDefaultFillLayout(true);
+  SetCornerRadius(kPickerImageItemCornerRadius);
 
   image_view_ = AddChildView(std::move(image));
   image_view_->SetCanProcessEventsWithinSubtree(false);
 
-  StyleUtil::InstallRoundedCornerHighlightPathGenerator(
-      this, kPickerImageItemCornerRadius);
-
   // TODO: b/316936418 - Get accessible name for image contents.
   SetAccessibleName(u"image contents");
 }
diff --git a/ash/picker/views/picker_item_view.cc b/ash/picker/views/picker_item_view.cc
index 9caeaa2e..10bc85f 100644
--- a/ash/picker/views/picker_item_view.cc
+++ b/ash/picker/views/picker_item_view.cc
@@ -4,16 +4,39 @@
 
 #include "ash/picker/views/picker_item_view.h"
 
+#include <memory>
 #include <utility>
 
+#include "ash/picker/views/picker_focus_indicator.h"
 #include "ash/style/style_util.h"
 #include "base/functional/callback.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
 #include "ui/compositor/layer.h"
 #include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rounded_corners_f.h"
+#include "ui/views/background.h"
 #include "ui/views/controls/button/button.h"
 
 namespace ash {
+namespace {
+
+constexpr auto kPickerItemFocusIndicatorMargins = gfx::Insets::VH(6, 0);
+
+std::unique_ptr<views::Background> GetPickerItemBackground(
+    PickerItemView::ItemState item_state,
+    int corner_radius) {
+  switch (item_state) {
+    case PickerItemView::ItemState::kNormal:
+      return nullptr;
+    case PickerItemView::ItemState::kPseudoFocused:
+      return views::CreateThemedRoundedRectBackground(
+          cros_tokens::kCrosSysHoverOnSubtle, corner_radius);
+  }
+}
+
+}  // namespace
 
 PickerItemView::PickerItemView(SelectItemCallback select_item_callback)
     : views::Button(select_item_callback),
@@ -28,10 +51,49 @@
 
 PickerItemView::~PickerItemView() = default;
 
+void PickerItemView::PaintButtonContents(gfx::Canvas* canvas) {
+  views::Button::PaintButtonContents(canvas);
+
+  if (item_state_ == ItemState::kPseudoFocused) {
+    // TODO: b/326870199 - Check whether grid items should have different focus
+    // indicator styling to list items.
+    PaintPickerFocusIndicator(
+        canvas, gfx::Point(0, kPickerItemFocusIndicatorMargins.top()),
+        height() - kPickerItemFocusIndicatorMargins.height(),
+        GetColorProvider()->GetColor(cros_tokens::kCrosSysFocusRing));
+  }
+}
+
 void PickerItemView::SelectItem() {
   select_item_callback_.Run();
 }
 
+void PickerItemView::SetCornerRadius(int corner_radius) {
+  if (corner_radius_ == corner_radius) {
+    return;
+  }
+
+  corner_radius_ = corner_radius;
+  StyleUtil::InstallRoundedCornerHighlightPathGenerator(
+      this, gfx::RoundedCornersF(corner_radius_));
+  SetBackground(GetPickerItemBackground(item_state_, corner_radius_));
+}
+
+PickerItemView::ItemState PickerItemView::GetItemState() const {
+  return item_state_;
+}
+
+void PickerItemView::SetItemState(ItemState item_state) {
+  if (item_state_ == item_state) {
+    return;
+  }
+
+  item_state_ = item_state;
+  SetBackground(GetPickerItemBackground(item_state_, corner_radius_));
+  // Schedule paint to update pseudo focus indicator.
+  SchedulePaint();
+}
+
 BEGIN_METADATA(PickerItemView)
 END_METADATA
 
diff --git a/ash/picker/views/picker_item_view.h b/ash/picker/views/picker_item_view.h
index 5ecd3c3..1edce94 100644
--- a/ash/picker/views/picker_item_view.h
+++ b/ash/picker/views/picker_item_view.h
@@ -17,6 +17,18 @@
   METADATA_HEADER(PickerItemView, views::Button)
 
  public:
+  // Used to determine how the item looks and how the user can interact with it.
+  enum class ItemState {
+    // Normal state.
+    kNormal,
+    // Pseudo focused state. The item is painted as if it was focused to
+    // indicate that it responds to certain user actions, e.g. it can be
+    // selected if the user presses the enter key. Note that the item might not
+    // have actual view focus (which generally stays on the Picker search field
+    // to allow the user to easily type and modify their search query).
+    kPseudoFocused,
+  };
+
   using SelectItemCallback = base::RepeatingClosure;
 
   explicit PickerItemView(SelectItemCallback select_item_callback);
@@ -24,10 +36,23 @@
   PickerItemView& operator=(const PickerItemView&) = delete;
   ~PickerItemView() override;
 
+  // views::Button:
+  void PaintButtonContents(gfx::Canvas* canvas) override;
+
   void SelectItem();
 
+  void SetCornerRadius(int corner_radius);
+
+  ItemState GetItemState() const;
+  void SetItemState(ItemState item_state);
+
  private:
   SelectItemCallback select_item_callback_;
+
+  ItemState item_state_ = ItemState::kNormal;
+
+  // Corner radius of the item background and highlight.
+  int corner_radius_ = 0;
 };
 
 }  // namespace ash
diff --git a/ash/picker/views/picker_item_view_unittest.cc b/ash/picker/views/picker_item_view_unittest.cc
new file mode 100644
index 0000000..1c3d5c6
--- /dev/null
+++ b/ash/picker/views/picker_item_view_unittest.cc
@@ -0,0 +1,36 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/picker/views/picker_item_view.h"
+
+#include "base/functional/callback_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ash {
+namespace {
+
+TEST(PickerItemViewTest, DefaultIsNormalState) {
+  PickerItemView item_view(base::DoNothing());
+
+  EXPECT_EQ(item_view.GetItemState(), PickerItemView::ItemState::kNormal);
+}
+
+TEST(PickerItemViewTest, NoBackgroundInNormalState) {
+  PickerItemView item_view(base::DoNothing());
+
+  item_view.SetItemState(PickerItemView::ItemState::kNormal);
+
+  EXPECT_FALSE(item_view.background());
+}
+
+TEST(PickerItemViewTest, HasBackgroundInPseudoFocusedState) {
+  PickerItemView item_view(base::DoNothing());
+
+  item_view.SetItemState(PickerItemView::ItemState::kPseudoFocused);
+
+  EXPECT_TRUE(item_view.background());
+}
+
+}  // namespace
+}  // namespace ash
diff --git a/ash/picker/views/picker_key_event_handler.cc b/ash/picker/views/picker_key_event_handler.cc
index 5b4eb23..5a1299b 100644
--- a/ash/picker/views/picker_key_event_handler.cc
+++ b/ash/picker/views/picker_key_event_handler.cc
@@ -4,7 +4,7 @@
 
 #include "ash/picker/views/picker_key_event_handler.h"
 
-#include "ash/picker/views/picker_key_event_target.h"
+#include "ash/picker/views/picker_pseudo_focus_handler.h"
 #include "ui/events/event.h"
 #include "ui/events/keycodes/keyboard_codes.h"
 
@@ -15,20 +15,37 @@
 PickerKeyEventHandler::~PickerKeyEventHandler() = default;
 
 bool PickerKeyEventHandler::HandleKeyEvent(const ui::KeyEvent& event) {
-  if (active_key_event_target_ == nullptr) {
+  if (active_pseudo_focus_handler_ == nullptr || event.handled() ||
+      event.type() != ui::ET_KEY_PRESSED) {
     return false;
   }
 
-  if (event.key_code() == ui::VKEY_RETURN) {
-    return active_key_event_target_->OnEnterKeyPressed();
+  const bool has_modifier =
+      event.IsShiftDown() || event.IsControlDown() || event.IsAltDown();
+  switch (event.key_code()) {
+    case ui::VKEY_RETURN:
+      return active_pseudo_focus_handler_->DoPseudoFocusedAction();
+    case ui::VKEY_UP:
+      return has_modifier ? false
+                          : active_pseudo_focus_handler_->MovePseudoFocusUp();
+    case ui::VKEY_DOWN:
+      return has_modifier ? false
+                          : active_pseudo_focus_handler_->MovePseudoFocusDown();
+    case ui::VKEY_LEFT:
+      return has_modifier ? false
+                          : active_pseudo_focus_handler_->MovePseudoFocusLeft();
+    case ui::VKEY_RIGHT:
+      return has_modifier
+                 ? false
+                 : active_pseudo_focus_handler_->MovePseudoFocusRight();
+    default:
+      return false;
   }
-
-  return false;
 }
 
-void PickerKeyEventHandler::SetActiveKeyEventTarget(
-    PickerKeyEventTarget* active_key_event_target) {
-  active_key_event_target_ = active_key_event_target;
+void PickerKeyEventHandler::SetActivePseudoFocusHandler(
+    PickerPseudoFocusHandler* active_pseudo_focus_handler) {
+  active_pseudo_focus_handler_ = active_pseudo_focus_handler;
 }
 
 }  // namespace ash
diff --git a/ash/picker/views/picker_key_event_handler.h b/ash/picker/views/picker_key_event_handler.h
index 3f72008b..5f4f0e6 100644
--- a/ash/picker/views/picker_key_event_handler.h
+++ b/ash/picker/views/picker_key_event_handler.h
@@ -14,7 +14,7 @@
 
 namespace ash {
 
-class PickerKeyEventTarget;
+class PickerPseudoFocusHandler;
 
 // Helper for routing and handling key events, e.g. for keyboard navigation.
 class ASH_EXPORT PickerKeyEventHandler {
@@ -28,10 +28,11 @@
   // processed.
   bool HandleKeyEvent(const ui::KeyEvent& event);
 
-  void SetActiveKeyEventTarget(PickerKeyEventTarget* active_key_event_target);
+  void SetActivePseudoFocusHandler(
+      PickerPseudoFocusHandler* active_pseudo_focus_handler);
 
  private:
-  raw_ptr<PickerKeyEventTarget> active_key_event_target_ = nullptr;
+  raw_ptr<PickerPseudoFocusHandler> active_pseudo_focus_handler_ = nullptr;
 };
 
 }  // namespace ash
diff --git a/ash/picker/views/picker_key_event_handler_unittest.cc b/ash/picker/views/picker_key_event_handler_unittest.cc
index 51f75df..dac2192 100644
--- a/ash/picker/views/picker_key_event_handler_unittest.cc
+++ b/ash/picker/views/picker_key_event_handler_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "ash/picker/views/picker_key_event_handler.h"
 
-#include "ash/picker/views/picker_key_event_target.h"
+#include "ash/picker/views/picker_pseudo_focus_handler.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/events/base_event_utils.h"
 #include "ui/events/event.h"
@@ -16,37 +16,60 @@
 namespace ash {
 namespace {
 
-ui::KeyEvent CreateKeyEvent(ui::KeyboardCode key_code) {
-  return ui::KeyEvent(ui::ET_KEY_PRESSED, key_code, ui::DomCode::NONE,
-                      ui::EF_NONE, ui::EventTimeForNow());
+ui::KeyEvent CreateKeyEvent(ui::KeyboardCode key_code,
+                            int flags = ui::EF_NONE) {
+  return ui::KeyEvent(ui::ET_KEY_PRESSED, key_code, ui::DomCode::NONE, flags,
+                      ui::EventTimeForNow());
 }
 
-class MockPickerKeyEventTarget : public PickerKeyEventTarget {
+class MockPseudoFocusHandler : public PickerPseudoFocusHandler {
  public:
-  MockPickerKeyEventTarget() = default;
-  MockPickerKeyEventTarget(const MockPickerKeyEventTarget&) = delete;
-  MockPickerKeyEventTarget& operator=(const MockPickerKeyEventTarget&) = delete;
-  ~MockPickerKeyEventTarget() override = default;
+  MockPseudoFocusHandler() = default;
+  MockPseudoFocusHandler(const MockPseudoFocusHandler&) = delete;
+  MockPseudoFocusHandler& operator=(const MockPseudoFocusHandler&) = delete;
+  ~MockPseudoFocusHandler() override = default;
 
-  // PickerKeyEventTarget:
-  bool OnEnterKeyPressed() override { return true; }
+  // PickerPseudoFocusHandler:
+  bool DoPseudoFocusedAction() override { return true; }
+  bool MovePseudoFocusUp() override { return true; }
+  bool MovePseudoFocusDown() override { return true; }
+  bool MovePseudoFocusLeft() override { return true; }
+  bool MovePseudoFocusRight() override { return true; }
 };
 
-TEST(PickerKeyEventHandlerTest, DoesNotHandleEnterKeyWithoutKeyEventTarget) {
+TEST(PickerKeyEventHandlerTest,
+     DoesNotHandleKeyEventyWithoutPseudoFocusHandler) {
   PickerKeyEventHandler key_event_handler;
 
   EXPECT_FALSE(
       key_event_handler.HandleKeyEvent(CreateKeyEvent(ui::VKEY_RETURN)));
 }
 
-TEST(PickerKeyEventHandlerTest, HandlesEnterKeyWithKeyEventTarget) {
+TEST(PickerKeyEventHandlerTest, HandlesKeyEventWithPseudoFocusHandler) {
   PickerKeyEventHandler key_event_handler;
-  MockPickerKeyEventTarget key_event_target;
-  key_event_handler.SetActiveKeyEventTarget(&key_event_target);
+  MockPseudoFocusHandler pseudo_focus_handler;
+  key_event_handler.SetActivePseudoFocusHandler(&pseudo_focus_handler);
 
   EXPECT_TRUE(
       key_event_handler.HandleKeyEvent(CreateKeyEvent(ui::VKEY_RETURN)));
 }
 
+TEST(PickerKeyEventHandlerTest, HandlesUnmodifedArrowKeyEvent) {
+  PickerKeyEventHandler key_event_handler;
+  MockPseudoFocusHandler pseudo_focus_handler;
+  key_event_handler.SetActivePseudoFocusHandler(&pseudo_focus_handler);
+
+  EXPECT_TRUE(key_event_handler.HandleKeyEvent(CreateKeyEvent(ui::VKEY_UP)));
+}
+
+TEST(PickerKeyEventHandlerTest, DoesNotHandleModifiedArrowKeyEvent) {
+  PickerKeyEventHandler key_event_handler;
+  MockPseudoFocusHandler pseudo_focus_handler;
+  key_event_handler.SetActivePseudoFocusHandler(&pseudo_focus_handler);
+
+  EXPECT_FALSE(key_event_handler.HandleKeyEvent(
+      CreateKeyEvent(ui::VKEY_UP, ui::EF_SHIFT_DOWN)));
+}
+
 }  // namespace
 }  // namespace ash
diff --git a/ash/picker/views/picker_key_event_target.h b/ash/picker/views/picker_key_event_target.h
deleted file mode 100644
index 6a77297..0000000
--- a/ash/picker/views/picker_key_event_target.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_PICKER_VIEWS_PICKER_KEY_EVENT_TARGET_H_
-#define ASH_PICKER_VIEWS_PICKER_KEY_EVENT_TARGET_H_
-
-#include "ash/ash_export.h"
-
-namespace ash {
-
-class ASH_EXPORT PickerKeyEventTarget {
- public:
-  virtual ~PickerKeyEventTarget() = default;
-
-  // Returns true if the enter key press was handled and should not be further
-  // processed.
-  virtual bool OnEnterKeyPressed() = 0;
-};
-
-}  // namespace ash
-
-#endif  // ASH_PICKER_VIEWS_PICKER_KEY_EVENT_TARGET_H_
diff --git a/ash/picker/views/picker_list_item_container_view.cc b/ash/picker/views/picker_list_item_container_view.cc
index 53bd8fc2..2a74b2d 100644
--- a/ash/picker/views/picker_list_item_container_view.cc
+++ b/ash/picker/views/picker_list_item_container_view.cc
@@ -10,6 +10,7 @@
 
 #include "ash/picker/views/picker_item_view.h"
 #include "ash/picker/views/picker_list_item_view.h"
+#include "base/ranges/algorithm.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/views/layout/flex_layout.h"
 #include "ui/views/layout/layout_types.h"
@@ -39,32 +40,32 @@
 }
 
 PickerItemView* PickerListItemContainerView::GetItemAbove(
-    const PickerItemView* item) {
-  const views::View::Views::const_iterator it = FindChild(item);
-  return it == children().cend() || it == children().cbegin()
+    PickerItemView* item) {
+  const auto it = base::ranges::find(children(), item);
+  return it == children().end() || it == children().begin()
              ? nullptr
              : views::AsViewClass<PickerItemView>(std::prev(it)->get());
 }
 
 PickerItemView* PickerListItemContainerView::GetItemBelow(
-    const PickerItemView* item) {
-  const views::View::Views::const_iterator it = FindChild(item);
-  if (it == children().cend()) {
+    PickerItemView* item) {
+  const auto it = base::ranges::find(children(), item);
+  if (it == children().end()) {
     return nullptr;
   }
-  const views::View::Views::const_iterator next_it = std::next(it);
-  return next_it == children().cend()
+  const auto next_it = std::next(it);
+  return next_it == children().end()
              ? nullptr
              : views::AsViewClass<PickerItemView>(next_it->get());
 }
 
 PickerItemView* PickerListItemContainerView::GetItemLeftOf(
-    const PickerItemView* item) {
+    PickerItemView* item) {
   return nullptr;
 }
 
 PickerItemView* PickerListItemContainerView::GetItemRightOf(
-    const PickerItemView* item) {
+    PickerItemView* item) {
   return nullptr;
 }
 
diff --git a/ash/picker/views/picker_list_item_container_view.h b/ash/picker/views/picker_list_item_container_view.h
index e175450..6bf58fe 100644
--- a/ash/picker/views/picker_list_item_container_view.h
+++ b/ash/picker/views/picker_list_item_container_view.h
@@ -34,10 +34,10 @@
   // PickerTraversableItemContainer:
   PickerItemView* GetTopItem() override;
   PickerItemView* GetBottomItem() override;
-  PickerItemView* GetItemAbove(const PickerItemView* item) override;
-  PickerItemView* GetItemBelow(const PickerItemView* item) override;
-  PickerItemView* GetItemLeftOf(const PickerItemView* item) override;
-  PickerItemView* GetItemRightOf(const PickerItemView* item) override;
+  PickerItemView* GetItemAbove(PickerItemView* item) override;
+  PickerItemView* GetItemBelow(PickerItemView* item) override;
+  PickerItemView* GetItemLeftOf(PickerItemView* item) override;
+  PickerItemView* GetItemRightOf(PickerItemView* item) override;
 
   PickerListItemView* AddListItem(
       std::unique_ptr<PickerListItemView> list_item);
diff --git a/ash/picker/views/picker_page_view.h b/ash/picker/views/picker_page_view.h
index a9aacdb..cb44aeaf 100644
--- a/ash/picker/views/picker_page_view.h
+++ b/ash/picker/views/picker_page_view.h
@@ -6,7 +6,7 @@
 #define ASH_PICKER_VIEWS_PICKER_PAGE_VIEW_H_
 
 #include "ash/ash_export.h"
-#include "ash/picker/views/picker_key_event_target.h"
+#include "ash/picker/views/picker_pseudo_focus_handler.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/views/view.h"
 
@@ -14,7 +14,7 @@
 
 // View for a page that can act as the main contents of the Picker.
 class ASH_EXPORT PickerPageView : public views::View,
-                                  public PickerKeyEventTarget {
+                                  public PickerPseudoFocusHandler {
   METADATA_HEADER(PickerPageView, views::View)
 };
 
diff --git a/ash/picker/views/picker_positioning.cc b/ash/picker/views/picker_positioning.cc
new file mode 100644
index 0000000..a2bd4b8f
--- /dev/null
+++ b/ash/picker/views/picker_positioning.cc
@@ -0,0 +1,32 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/picker/views/picker_positioning.h"
+
+#include "ui/gfx/geometry/outsets.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace ash {
+namespace {
+
+// Padding to separate the Picker window from the caret.
+constexpr gfx::Outsets kPaddingAroundCaret(4);
+
+}  // namespace
+
+gfx::Rect GetPickerAnchorBounds(const gfx::Rect& caret_bounds,
+                                const gfx::Point& cursor_point,
+                                const gfx::Rect& focused_window_bounds) {
+  if (caret_bounds != gfx::Rect() &&
+      focused_window_bounds.Contains(caret_bounds)) {
+    gfx::Rect anchor_rect = caret_bounds;
+    anchor_rect.Outset(kPaddingAroundCaret);
+    return anchor_rect;
+  } else {
+    return gfx::Rect(cursor_point, gfx::Size());
+  }
+}
+
+}  // namespace ash
diff --git a/ash/picker/views/picker_positioning.h b/ash/picker/views/picker_positioning.h
new file mode 100644
index 0000000..692f222
--- /dev/null
+++ b/ash/picker/views/picker_positioning.h
@@ -0,0 +1,28 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_PICKER_VIEWS_PICKER_POSITIONING_H_
+#define ASH_PICKER_VIEWS_PICKER_POSITIONING_H_
+
+#include "ash/ash_export.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace gfx {
+class Point;
+}  // namespace gfx
+
+namespace ash {
+
+// Gets the anchor bounds to use for positioning the Picker. We prefer to anchor
+// at `caret_bounds`, but may use `cursor_point` as a fallback. `caret_bounds`,
+// `cursor_point`, `focused_window_bounds` and returned anchor bounds should be
+// in screen coordinates.
+gfx::Rect ASH_EXPORT
+GetPickerAnchorBounds(const gfx::Rect& caret_bounds,
+                      const gfx::Point& cursor_point,
+                      const gfx::Rect& focused_window_bounds);
+
+}  // namespace ash
+
+#endif  // ASH_PICKER_VIEWS_PICKER_POSITIONING_H_
diff --git a/ash/picker/views/picker_positioning_unittest.cc b/ash/picker/views/picker_positioning_unittest.cc
new file mode 100644
index 0000000..5f04de87
--- /dev/null
+++ b/ash/picker/views/picker_positioning_unittest.cc
@@ -0,0 +1,52 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/picker/views/picker_positioning.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/outsets.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace ash {
+namespace {
+
+constexpr gfx::Outsets kPaddingAroundCaret(4);
+constexpr gfx::Point kDefaultCursorPoint(42, 42);
+
+TEST(PickerPositioningTest,
+     UsesCaretBoundsWhenCaretBoundsIsWithinWindowBounds) {
+  gfx::Rect caret_bounds(100, 200, 5, 5);
+  const gfx::Rect anchor_bounds = GetPickerAnchorBounds(
+      /*caret_bounds=*/caret_bounds, kDefaultCursorPoint,
+      /*focused_window_bounds=*/gfx::Rect(0, 0, 500, 500));
+
+  caret_bounds.Outset(kPaddingAroundCaret);
+  EXPECT_EQ(anchor_bounds, caret_bounds);
+}
+
+TEST(PickerPositioningTest,
+     UsesCursorPointWhenCaretBoundsIsOutsideWindowBounds) {
+  const gfx::Rect anchor_bounds = GetPickerAnchorBounds(
+      /*caret_bounds=*/gfx::Rect(600, 200, 5, 5), kDefaultCursorPoint,
+      /*focused_window_bounds=*/gfx::Rect(0, 0, 500, 500));
+
+  EXPECT_EQ(anchor_bounds.origin(), kDefaultCursorPoint);
+  EXPECT_EQ(anchor_bounds.width(), 0);
+  EXPECT_EQ(anchor_bounds.height(), 0);
+}
+
+TEST(PickerPositioningTest, UsesCursorPointWhenCaretBoundsIsEmpty) {
+  const gfx::Rect anchor_bounds = GetPickerAnchorBounds(
+      /*caret_bounds=*/gfx::Rect(), kDefaultCursorPoint,
+      /*focused_window_bounds=*/gfx::Rect(0, 0, 500, 500));
+
+  EXPECT_EQ(anchor_bounds.origin(), kDefaultCursorPoint);
+  EXPECT_EQ(anchor_bounds.width(), 0);
+  EXPECT_EQ(anchor_bounds.height(), 0);
+}
+
+}  // namespace
+}  // namespace ash
diff --git a/ash/picker/views/picker_pseudo_focus_handler.h b/ash/picker/views/picker_pseudo_focus_handler.h
new file mode 100644
index 0000000..87b7f064
--- /dev/null
+++ b/ash/picker/views/picker_pseudo_focus_handler.h
@@ -0,0 +1,33 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_PICKER_VIEWS_PICKER_PSEUDO_FOCUS_HANDLER_H_
+#define ASH_PICKER_VIEWS_PICKER_PSEUDO_FOCUS_HANDLER_H_
+
+#include "ash/ash_export.h"
+
+namespace ash {
+
+// Interface for classes that have pseudo focusable elements, which can look and
+// behave as if they were focused without having actual focus. We use "pseudo
+// focus" since actual view focus generally stays on the Picker search field,
+// which just forwards user actions to be handled by pseudo focused elements if
+// needed (e.g. to select an item when the user presses the enter key).
+class ASH_EXPORT PickerPseudoFocusHandler {
+ public:
+  virtual ~PickerPseudoFocusHandler() = default;
+
+  // Returns true if an action was performed.
+  virtual bool DoPseudoFocusedAction() = 0;
+
+  // Returns true if pseudo focus was moved to a different element.
+  virtual bool MovePseudoFocusUp() = 0;
+  virtual bool MovePseudoFocusDown() = 0;
+  virtual bool MovePseudoFocusLeft() = 0;
+  virtual bool MovePseudoFocusRight() = 0;
+};
+
+}  // namespace ash
+
+#endif  // ASH_PICKER_VIEWS_PICKER_PSEUDO_FOCUS_HANDLER_H_
diff --git a/ash/picker/views/picker_search_results_view.cc b/ash/picker/views/picker_search_results_view.cc
index 88d5038..4fbb20b 100644
--- a/ash/picker/views/picker_search_results_view.cc
+++ b/ash/picker/views/picker_search_results_view.cc
@@ -19,6 +19,7 @@
 #include "ash/picker/views/picker_image_item_view.h"
 #include "ash/picker/views/picker_item_view.h"
 #include "ash/picker/views/picker_list_item_view.h"
+#include "ash/picker/views/picker_section_list_view.h"
 #include "ash/picker/views/picker_section_view.h"
 #include "ash/picker/views/picker_strings.h"
 #include "ash/picker/views/picker_symbol_item_view.h"
@@ -40,41 +41,102 @@
     int picker_view_width,
     SelectSearchResultCallback select_search_result_callback,
     PickerAssetFetcher* asset_fetcher)
-    : picker_view_width_(picker_view_width),
-      select_search_result_callback_(std::move(select_search_result_callback)),
+    : select_search_result_callback_(std::move(select_search_result_callback)),
       asset_fetcher_(asset_fetcher) {
   SetLayoutManager(std::make_unique<views::FlexLayout>())
       ->SetOrientation(views::LayoutOrientation::kVertical);
   SetProperty(views::kElementIdentifierKey, kPickerSearchResultsPageElementId);
+
+  section_list_view_ =
+      AddChildView(std::make_unique<PickerSectionListView>(picker_view_width));
 }
 
 PickerSearchResultsView::~PickerSearchResultsView() = default;
 
-bool PickerSearchResultsView::OnEnterKeyPressed() {
-  // TODO: b/322900302 - Select the currently highlighted item instead of the
-  // first item.
-  if (section_views_.empty() || section_views_[0]->item_views().empty()) {
+bool PickerSearchResultsView::DoPseudoFocusedAction() {
+  if (pseudo_focused_item_ == nullptr) {
     return false;
   }
-  section_views_[0]->item_views()[0]->SelectItem();
+
+  pseudo_focused_item_->SelectItem();
+  return true;
+}
+
+bool PickerSearchResultsView::MovePseudoFocusUp() {
+  if (pseudo_focused_item_ == nullptr) {
+    return false;
+  }
+
+  PickerItemView* item = section_list_view_->GetItemAbove(pseudo_focused_item_);
+  if (item == nullptr) {
+    // If there's no item above, move pseudo focus to the bottom item.
+    item = section_list_view_->GetBottomItem();
+  }
+  SetPseudoFocusedItem(item);
+  return true;
+}
+
+bool PickerSearchResultsView::MovePseudoFocusDown() {
+  if (pseudo_focused_item_ == nullptr) {
+    return false;
+  }
+
+  PickerItemView* item = section_list_view_->GetItemBelow(pseudo_focused_item_);
+  if (item == nullptr) {
+    // If there's no item below, move pseudo focus to the top item.
+    item = section_list_view_->GetTopItem();
+  }
+  SetPseudoFocusedItem(item);
+  return true;
+}
+
+bool PickerSearchResultsView::MovePseudoFocusLeft() {
+  if (pseudo_focused_item_ == nullptr) {
+    return false;
+  }
+
+  PickerItemView* item =
+      section_list_view_->GetItemLeftOf(pseudo_focused_item_);
+  if (item == nullptr) {
+    return false;
+  }
+  SetPseudoFocusedItem(item);
+  return true;
+}
+
+bool PickerSearchResultsView::MovePseudoFocusRight() {
+  if (pseudo_focused_item_ == nullptr) {
+    return false;
+  }
+
+  PickerItemView* item =
+      section_list_view_->GetItemRightOf(pseudo_focused_item_);
+  if (item == nullptr) {
+    return false;
+  }
+  SetPseudoFocusedItem(item);
   return true;
 }
 
 void PickerSearchResultsView::ClearSearchResults() {
+  pseudo_focused_item_ = nullptr;
   section_views_.clear();
-  RemoveAllChildViews();
+  section_list_view_->ClearSectionList();
 }
 
 void PickerSearchResultsView::AppendSearchResults(
     PickerSearchResultsSection section) {
-  auto* section_view =
-      AddChildView(std::make_unique<PickerSectionView>(picker_view_width_));
+  auto* section_view = section_list_view_->AddSection();
   section_view->AddTitleLabel(
       GetSectionTitleForPickerSectionType(section.type()));
   for (const auto& result : section.results()) {
     AddResultToSection(result, section_view);
   }
   section_views_.push_back(section_view);
+
+  if (pseudo_focused_item_ == nullptr) {
+    SetPseudoFocusedItem(section_list_view_->GetTopItem());
+  }
 }
 
 void PickerSearchResultsView::SelectSearchResult(
@@ -120,11 +182,13 @@
             // view and `asset_fetcher_` outlives `this`.
             auto gif_view = std::make_unique<PickerGifView>(
                 base::BindRepeating(&PickerAssetFetcher::FetchGifFromUrl,
-                                    base::Unretained(asset_fetcher_), data.url),
+                                    base::Unretained(asset_fetcher_),
+                                    data.preview_url),
                 base::BindRepeating(
                     &PickerAssetFetcher::FetchGifPreviewImageFromUrl,
                     base::Unretained(asset_fetcher_), data.preview_image_url),
-                data.dimensions, /*accessible_name=*/data.content_description);
+                data.preview_dimensions,
+                /*accessible_name=*/data.content_description);
             auto gif_item_view = std::make_unique<PickerImageItemView>(
                 std::move(select_result_callback), std::move(gif_view));
             section_view->AddImageItem(std::move(gif_item_view));
@@ -148,6 +212,44 @@
       result.data());
 }
 
+void PickerSearchResultsView::SetPseudoFocusedItem(PickerItemView* item) {
+  if (pseudo_focused_item_ == item) {
+    return;
+  }
+
+  if (pseudo_focused_item_ != nullptr) {
+    pseudo_focused_item_->SetItemState(PickerItemView::ItemState::kNormal);
+  }
+
+  pseudo_focused_item_ = item;
+
+  if (pseudo_focused_item_ != nullptr) {
+    pseudo_focused_item_->SetItemState(
+        PickerItemView::ItemState::kPseudoFocused);
+    ScrollPseudoFocusedItemToVisible();
+  }
+}
+
+void PickerSearchResultsView::ScrollPseudoFocusedItemToVisible() {
+  if (pseudo_focused_item_ == nullptr) {
+    return;
+  }
+
+  if (section_list_view_->GetItemAbove(pseudo_focused_item_) == nullptr) {
+    // For items at the top, scroll all the way up to let users see that they
+    // have reached the top of the zero state view.
+    ScrollRectToVisible(gfx::Rect(GetLocalBounds().origin(), gfx::Size()));
+  } else if (section_list_view_->GetItemBelow(pseudo_focused_item_) ==
+             nullptr) {
+    // For items at the bottom, scroll all the way down to let users see that
+    // they have reached the bottom of the zero state view.
+    ScrollRectToVisible(gfx::Rect(GetLocalBounds().bottom_left(), gfx::Size()));
+  } else {
+    // Otherwise, just ensure the item is visible.
+    pseudo_focused_item_->ScrollViewToVisible();
+  }
+}
+
 BEGIN_METADATA(PickerSearchResultsView)
 END_METADATA
 
diff --git a/ash/picker/views/picker_search_results_view.h b/ash/picker/views/picker_search_results_view.h
index 4b4ee969..642d72d 100644
--- a/ash/picker/views/picker_search_results_view.h
+++ b/ash/picker/views/picker_search_results_view.h
@@ -16,7 +16,9 @@
 namespace ash {
 
 class PickerAssetFetcher;
+class PickerItemView;
 class PickerSearchResult;
+class PickerSectionListView;
 class PickerSectionView;
 
 class ASH_EXPORT PickerSearchResultsView : public PickerPageView {
@@ -37,7 +39,11 @@
   ~PickerSearchResultsView() override;
 
   // PickerPageView:
-  bool OnEnterKeyPressed() override;
+  bool DoPseudoFocusedAction() override;
+  bool MovePseudoFocusUp() override;
+  bool MovePseudoFocusDown() override;
+  bool MovePseudoFocusLeft() override;
+  bool MovePseudoFocusRight() override;
 
   // Clears the search results.
   void ClearSearchResults();
@@ -46,6 +52,10 @@
   // TODO: b/325840864 - Merge with existing sections if needed.
   void AppendSearchResults(PickerSearchResultsSection section);
 
+  const PickerSectionListView* section_list_view_for_testing() const {
+    return section_list_view_;
+  }
+
   base::span<const raw_ptr<PickerSectionView>> section_views_for_testing()
       const {
     return section_views_;
@@ -61,16 +71,24 @@
   void AddResultToSection(const PickerSearchResult& result,
                           PickerSectionView* section_view);
 
-  // Width of the containing PickerView.
-  int picker_view_width_ = 0;
+  void SetPseudoFocusedItem(PickerItemView* item);
+
+  void ScrollPseudoFocusedItemToVisible();
 
   SelectSearchResultCallback select_search_result_callback_;
 
   // `asset_fetcher` outlives `this`.
   raw_ptr<PickerAssetFetcher> asset_fetcher_ = nullptr;
 
-  // The views for each section of results.
+  // The section list view, contains the section views.
+  raw_ptr<PickerSectionListView> section_list_view_ = nullptr;
+
+  // Used to track the views for each section of results.
   std::vector<raw_ptr<PickerSectionView>> section_views_;
+
+  // The currently pseudo focused item, which responds to user actions that
+  // trigger `DoPseudoFocusedAction`.
+  raw_ptr<PickerItemView> pseudo_focused_item_ = nullptr;
 };
 
 }  // namespace ash
diff --git a/ash/picker/views/picker_search_results_view_unittest.cc b/ash/picker/views/picker_search_results_view_unittest.cc
index 055f2c40..51062ee 100644
--- a/ash/picker/views/picker_search_results_view_unittest.cc
+++ b/ash/picker/views/picker_search_results_view_unittest.cc
@@ -4,12 +4,16 @@
 
 #include "ash/picker/views/picker_search_results_view.h"
 
+#include <string>
+
 #include "ash/picker/mock_picker_asset_fetcher.h"
 #include "ash/picker/model/picker_search_results_section.h"
 #include "ash/picker/picker_test_util.h"
 #include "ash/picker/views/picker_item_view.h"
+#include "ash/picker/views/picker_section_list_view.h"
 #include "ash/picker/views/picker_section_view.h"
 #include "ash/picker/views/picker_strings.h"
+#include "ash/public/cpp/picker/picker_search_result.h"
 #include "ash/style/ash_color_provider.h"
 #include "ash/test/view_drawn_waiter.h"
 #include "base/functional/callback_helpers.h"
@@ -17,6 +21,7 @@
 #include "testing/gmock/include/gmock/gmock-matchers.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/size.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/test/views_test_base.h"
 #include "ui/views/widget/widget.h"
@@ -56,7 +61,7 @@
       PickerSectionType::kLinks, {{PickerSearchResult::Text(u"Result B"),
                                    PickerSearchResult::Text(u"Result C")}}));
 
-  EXPECT_THAT(view.children(), SizeIs(2));
+  EXPECT_THAT(view.section_list_view_for_testing()->children(), SizeIs(2));
   EXPECT_THAT(
       view.section_views_for_testing(),
       ElementsAre(
@@ -73,7 +78,7 @@
 
   view.ClearSearchResults();
 
-  EXPECT_THAT(view.children(), IsEmpty());
+  EXPECT_THAT(view.section_list_view_for_testing()->children(), IsEmpty());
 }
 
 TEST_F(PickerSearchResultsViewTest, CreatesResultsSectionWithGif) {
@@ -83,10 +88,11 @@
   view.AppendSearchResults(PickerSearchResultsSection(
       PickerSectionType::kGifs,
       {{PickerSearchResult::Gif(
-          /*url=*/GURL(), /*preview_image_url=*/GURL(), gfx::Size(),
+          /*preview_url=*/GURL(), /*preview_image_url=*/GURL(), gfx::Size(),
+          /*full_url=*/GURL(), gfx::Size(),
           /*content_description=*/u"")}}));
 
-  EXPECT_THAT(view.children(), SizeIs(1));
+  EXPECT_THAT(view.section_list_view_for_testing()->children(), SizeIs(1));
   EXPECT_THAT(
       view.section_views_for_testing(),
       ElementsAre(Pointee(MatchesResultSection(PickerSectionType::kGifs, 1))));
@@ -100,7 +106,7 @@
       PickerSectionType::kCategories,
       {{PickerSearchResult::Category(PickerCategory::kEmojis)}}));
 
-  EXPECT_THAT(view.children(), SizeIs(1));
+  EXPECT_THAT(view.section_list_view_for_testing()->children(), SizeIs(1));
   EXPECT_THAT(view.section_views_for_testing(),
               ElementsAre(Pointee(
                   MatchesResultSection(PickerSectionType::kCategories, 1))));
@@ -117,7 +123,7 @@
       PickerSectionType::kLinks,
       {{PickerSearchResult::Text(u"Updated Result")}}));
 
-  EXPECT_THAT(view.children(), SizeIs(2));
+  EXPECT_THAT(view.section_list_view_for_testing()->children(), SizeIs(2));
   EXPECT_THAT(
       view.section_views_for_testing(),
       ElementsAre(
@@ -126,11 +132,57 @@
 }
 
 TEST_F(PickerSearchResultsViewTest,
-       PressingEnterDoesNothingForEmptySearchResults) {
+       NoPseudoFocusedActionForEmptySearchResults) {
   MockPickerAssetFetcher asset_fetcher;
   PickerSearchResultsView view(kPickerWidth, base::DoNothing(), &asset_fetcher);
 
-  EXPECT_FALSE(view.OnEnterKeyPressed());
+  EXPECT_FALSE(view.DoPseudoFocusedAction());
+}
+
+TEST_F(PickerSearchResultsViewTest, PseudoFocusedActionDefaultsToFirstResult) {
+  base::test::TestFuture<const PickerSearchResult&> future;
+  MockPickerAssetFetcher asset_fetcher;
+  PickerSearchResultsView view(kPickerWidth, future.GetCallback(),
+                               &asset_fetcher);
+
+  view.AppendSearchResults(PickerSearchResultsSection(
+      PickerSectionType::kExpressions,
+      {{PickerSearchResult::Emoji(u"😊"), PickerSearchResult::Symbol(u"♬")}}));
+
+  EXPECT_TRUE(view.DoPseudoFocusedAction());
+  EXPECT_EQ(future.Get(), PickerSearchResult::Emoji(u"😊"));
+}
+
+TEST_F(PickerSearchResultsViewTest, MovesPseudoFocusRight) {
+  base::test::TestFuture<const PickerSearchResult&> future;
+  MockPickerAssetFetcher asset_fetcher;
+  PickerSearchResultsView view(kPickerWidth, future.GetCallback(),
+                               &asset_fetcher);
+
+  view.AppendSearchResults(PickerSearchResultsSection(
+      PickerSectionType::kExpressions,
+      {{PickerSearchResult::Emoji(u"😊"), PickerSearchResult::Symbol(u"♬")}}));
+
+  EXPECT_TRUE(view.MovePseudoFocusRight());
+  EXPECT_TRUE(view.DoPseudoFocusedAction());
+  EXPECT_EQ(future.Get(), PickerSearchResult::Symbol(u"♬"));
+}
+
+TEST_F(PickerSearchResultsViewTest, MovesPseudoFocusDown) {
+  base::test::TestFuture<const PickerSearchResult&> future;
+  MockPickerAssetFetcher asset_fetcher;
+  PickerSearchResultsView view(kPickerWidth, future.GetCallback(),
+                               &asset_fetcher);
+
+  view.AppendSearchResults(PickerSearchResultsSection(
+      PickerSectionType::kCategories,
+      {{PickerSearchResult::Category(PickerCategory::kEmojis),
+        PickerSearchResult::Category(PickerCategory::kEmoticons)}}));
+
+  EXPECT_TRUE(view.MovePseudoFocusDown());
+  EXPECT_TRUE(view.DoPseudoFocusedAction());
+  EXPECT_EQ(future.Get(),
+            PickerSearchResult::Category(PickerCategory::kEmoticons));
 }
 
 struct PickerSearchResultTestCase {
@@ -169,7 +221,8 @@
   EXPECT_EQ(future.Get(), test_case.result);
 }
 
-TEST_P(PickerSearchResultsViewResultSelectionTest, PressingEnterSelectsResult) {
+TEST_P(PickerSearchResultsViewResultSelectionTest,
+       PseudoFocusedActionSelectsResult) {
   const PickerSearchResultTestCase& test_case = GetParam();
   std::unique_ptr<views::Widget> widget = CreateTestWidget();
   widget->SetFullscreen(true);
@@ -181,7 +234,7 @@
   view->AppendSearchResults(PickerSearchResultsSection(
       PickerSectionType::kExpressions, {{test_case.result}}));
 
-  EXPECT_TRUE(view->OnEnterKeyPressed());
+  EXPECT_TRUE(view->DoPseudoFocusedAction());
   EXPECT_EQ(future.Get(), test_case.result);
 }
 
@@ -193,9 +246,11 @@
         {"Emoji", PickerSearchResult::Emoji(u"😊")},
         {"Symbol", PickerSearchResult::Symbol(u"♬")},
         {"Emoticon", PickerSearchResult::Emoticon(u"¯\\_(ツ)_/¯")},
-        {"Gif", PickerSearchResult::Gif(/*url=*/GURL(),
+        {"Gif", PickerSearchResult::Gif(/*preview_url=*/GURL(),
                                         /*preview_image_url=*/GURL(),
                                         gfx::Size(10, 10),
+                                        /*full_url=*/GURL(),
+                                        gfx::Size(20, 20),
                                         u"cat gif")},
         {"Category", PickerSearchResult::Category(PickerCategory::kEmojis)},
     }),
diff --git a/ash/picker/views/picker_section_list_view.cc b/ash/picker/views/picker_section_list_view.cc
new file mode 100644
index 0000000..a18ddcc
--- /dev/null
+++ b/ash/picker/views/picker_section_list_view.cc
@@ -0,0 +1,127 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/picker/views/picker_section_list_view.h"
+
+#include <iterator>
+#include <memory>
+#include <utility>
+
+#include "ash/picker/views/picker_item_view.h"
+#include "ash/picker/views/picker_section_view.h"
+#include "base/ranges/algorithm.h"
+#include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/views/layout/flex_layout.h"
+#include "ui/views/layout/layout_types.h"
+#include "ui/views/view.h"
+#include "ui/views/view_utils.h"
+
+namespace ash {
+
+PickerSectionListView::PickerSectionListView(int section_width)
+    : section_width_(section_width) {
+  SetLayoutManager(std::make_unique<views::FlexLayout>())
+      ->SetOrientation(views::LayoutOrientation::kVertical)
+      .SetCrossAxisAlignment(views::LayoutAlignment::kStretch);
+}
+
+PickerSectionListView::~PickerSectionListView() = default;
+
+PickerItemView* PickerSectionListView::GetTopItem() {
+  return children().empty()
+             ? nullptr
+             : views::AsViewClass<PickerSectionView>(children().front().get())
+                   ->GetTopItem();
+}
+
+PickerItemView* PickerSectionListView::GetBottomItem() {
+  return children().empty()
+             ? nullptr
+             : views::AsViewClass<PickerSectionView>(children().back().get())
+                   ->GetBottomItem();
+}
+
+PickerItemView* PickerSectionListView::GetItemAbove(PickerItemView* item) {
+  PickerSectionView* section = GetSectionContaining(item);
+  if (section == nullptr) {
+    return nullptr;
+  }
+
+  // First check if there is an item above in the same section.
+  if (PickerItemView* item_below = section->GetItemAbove(item)) {
+    return item_below;
+  }
+
+  // Otherwise, return the bottom item in a previous non-empty section if there
+  // is one.
+  for (auto section_it =
+           std::make_reverse_iterator(base::ranges::find(children(), section));
+       section_it != children().rend(); section_it = std::next(section_it)) {
+    if (PickerItemView* prev_section_bottom_item =
+            views::AsViewClass<PickerSectionView>(section_it->get())
+                ->GetBottomItem()) {
+      return prev_section_bottom_item;
+    }
+  }
+
+  return nullptr;
+}
+
+PickerItemView* PickerSectionListView::GetItemBelow(PickerItemView* item) {
+  PickerSectionView* section = GetSectionContaining(item);
+  if (section == nullptr) {
+    return nullptr;
+  }
+
+  // First check if there is an item below in the same section.
+  if (PickerItemView* item_below = section->GetItemBelow(item)) {
+    return item_below;
+  }
+
+  // Otherwise, return the top item in the next non-empty section if there is
+  // one.
+  for (auto section_it = std::next(base::ranges::find(children(), section));
+       section_it != children().end(); section_it = std::next(section_it)) {
+    if (PickerItemView* next_section_top_item =
+            views::AsViewClass<PickerSectionView>(section_it->get())
+                ->GetTopItem()) {
+      return next_section_top_item;
+    }
+  }
+  return nullptr;
+}
+
+PickerItemView* PickerSectionListView::GetItemLeftOf(PickerItemView* item) {
+  PickerSectionView* section = GetSectionContaining(item);
+  return section != nullptr ? section->GetItemLeftOf(item) : nullptr;
+}
+
+PickerItemView* PickerSectionListView::GetItemRightOf(PickerItemView* item) {
+  PickerSectionView* section = GetSectionContaining(item);
+  return section != nullptr ? section->GetItemRightOf(item) : nullptr;
+}
+
+PickerSectionView* PickerSectionListView::AddSection() {
+  return AddChildView(std::make_unique<PickerSectionView>(section_width_));
+}
+
+void PickerSectionListView::ClearSectionList() {
+  RemoveAllChildViews();
+}
+
+PickerSectionView* PickerSectionListView::GetSectionContaining(
+    PickerItemView* item) {
+  for (views::View* view = item->parent(); view != nullptr;
+       view = view->parent()) {
+    if (views::IsViewClass<PickerSectionView>(view) && view->parent() == this) {
+      return views::AsViewClass<PickerSectionView>(view);
+    }
+  }
+  return nullptr;
+}
+
+BEGIN_METADATA(PickerSectionListView)
+END_METADATA
+
+}  // namespace ash
diff --git a/ash/picker/views/picker_section_list_view.h b/ash/picker/views/picker_section_list_view.h
new file mode 100644
index 0000000..43db9f8
--- /dev/null
+++ b/ash/picker/views/picker_section_list_view.h
@@ -0,0 +1,68 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_PICKER_VIEWS_PICKER_SECTION_LIST_VIEW_H_
+#define ASH_PICKER_VIEWS_PICKER_SECTION_LIST_VIEW_H_
+
+#include "ash/ash_export.h"
+#include "ui/base/metadata/metadata_header_macros.h"
+#include "ui/views/view.h"
+
+namespace ash {
+
+class PickerItemView;
+class PickerSectionView;
+
+// View which displays Picker sections in a vertical list.
+class ASH_EXPORT PickerSectionListView : public views::View {
+  METADATA_HEADER(PickerSectionListView, views::View)
+
+ public:
+  explicit PickerSectionListView(int section_width);
+  PickerSectionListView(const PickerSectionListView&) = delete;
+  PickerSectionListView& operator=(const PickerSectionListView&) = delete;
+  ~PickerSectionListView() override;
+
+  // Returns the item to highlight to when navigating to this section list from
+  // the top, or nullptr if the section list is empty.
+  PickerItemView* GetTopItem();
+
+  // Returns the item to highlight to when navigating to this section list from
+  // the bottom, or nullptr if the section list is empty.
+  PickerItemView* GetBottomItem();
+
+  // Returns the item directly above `item`, or nullptr if there is no such item
+  // in the section list.
+  PickerItemView* GetItemAbove(PickerItemView* item);
+
+  // Returns the item directly below `item`, or nullptr if there is no such item
+  // in the section list.
+  PickerItemView* GetItemBelow(PickerItemView* item);
+
+  // Returns the item directly to the left of `item`, or nullptr if there is no
+  // such item in the section list.
+  PickerItemView* GetItemLeftOf(PickerItemView* item);
+
+  // Returns the item directly to the right of `item`, or nullptr if there is no
+  // such item in the section list.
+  PickerItemView* GetItemRightOf(PickerItemView* item);
+
+  // Adds a section to the end of the section list.
+  PickerSectionView* AddSection();
+
+  // Clears the section list. This deletes all contained sections and items.
+  void ClearSectionList();
+
+ private:
+  // Returns the section containing `item`, or nullptr if `item` is not part of
+  // this section list.
+  PickerSectionView* GetSectionContaining(PickerItemView* item);
+
+  // Width of the sections in this view.
+  int section_width_;
+};
+
+}  // namespace ash
+
+#endif  // ASH_PICKER_VIEWS_PICKER_SECTION_LIST_VIEW_H_
diff --git a/ash/picker/views/picker_section_list_view_unittest.cc b/ash/picker/views/picker_section_list_view_unittest.cc
new file mode 100644
index 0000000..53c2db2
--- /dev/null
+++ b/ash/picker/views/picker_section_list_view_unittest.cc
@@ -0,0 +1,188 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/picker/views/picker_section_list_view.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "ash/picker/views/picker_emoji_item_view.h"
+#include "ash/picker/views/picker_item_view.h"
+#include "ash/picker/views/picker_list_item_view.h"
+#include "ash/picker/views/picker_section_view.h"
+#include "ash/picker/views/picker_symbol_item_view.h"
+#include "base/functional/callback_helpers.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/view.h"
+
+namespace ash {
+namespace {
+
+using ::testing::ElementsAre;
+using ::testing::IsEmpty;
+
+constexpr int kDefaultSectionWidth = 320;
+
+using PickerSectionListViewTest = views::ViewsTestBase;
+
+TEST_F(PickerSectionListViewTest, AddsSection) {
+  PickerSectionListView section_list(kDefaultSectionWidth);
+
+  PickerSectionView* section = section_list.AddSection();
+
+  EXPECT_THAT(section_list.children(), ElementsAre(section));
+}
+
+TEST_F(PickerSectionListViewTest, ClearsSectionList) {
+  PickerSectionListView section_list(kDefaultSectionWidth);
+
+  section_list.AddSection();
+  section_list.ClearSectionList();
+
+  EXPECT_THAT(section_list.children(), IsEmpty());
+}
+
+TEST_F(PickerSectionListViewTest, GetsTopItem) {
+  PickerSectionListView section_list(kDefaultSectionWidth);
+
+  PickerSectionView* section1 = section_list.AddSection();
+  PickerItemView* top_item = section1->AddEmojiItem(
+      std::make_unique<PickerEmojiItemView>(base::DoNothing(), u"😊"));
+  section1->AddSymbolItem(
+      std::make_unique<PickerSymbolItemView>(base::DoNothing(), u"♬"));
+  PickerSectionView* section2 = section_list.AddSection();
+  section2->AddListItem(
+      std::make_unique<PickerListItemView>(base::DoNothing()));
+
+  EXPECT_EQ(section_list.GetTopItem(), top_item);
+}
+
+TEST_F(PickerSectionListViewTest, EmptySectionListHasNoTopItem) {
+  PickerSectionListView section_list(kDefaultSectionWidth);
+
+  EXPECT_EQ(section_list.GetTopItem(), nullptr);
+}
+
+TEST_F(PickerSectionListViewTest, GetsBottomItem) {
+  PickerSectionListView section_list(kDefaultSectionWidth);
+
+  PickerSectionView* section1 = section_list.AddSection();
+  section1->AddEmojiItem(
+      std::make_unique<PickerEmojiItemView>(base::DoNothing(), u"😊"));
+  section1->AddSymbolItem(
+      std::make_unique<PickerSymbolItemView>(base::DoNothing(), u"♬"));
+  PickerSectionView* section2 = section_list.AddSection();
+  PickerItemView* bottom_item = section2->AddListItem(
+      std::make_unique<PickerListItemView>(base::DoNothing()));
+
+  EXPECT_EQ(section_list.GetBottomItem(), bottom_item);
+}
+
+TEST_F(PickerSectionListViewTest, EmptySectionListHasNoBottomItem) {
+  PickerSectionListView section_list(kDefaultSectionWidth);
+
+  EXPECT_EQ(section_list.GetBottomItem(), nullptr);
+}
+
+TEST_F(PickerSectionListViewTest, GetsItemAbove) {
+  PickerSectionListView section_list(kDefaultSectionWidth);
+
+  PickerSectionView* section1 = section_list.AddSection();
+  PickerItemView* item1 = section1->AddEmojiItem(
+      std::make_unique<PickerEmojiItemView>(base::DoNothing(), u"😊"));
+  PickerItemView* item2 = section1->AddSymbolItem(
+      std::make_unique<PickerSymbolItemView>(base::DoNothing(), u"♬"));
+  PickerSectionView* section2 = section_list.AddSection();
+  PickerItemView* item3 = section2->AddListItem(
+      std::make_unique<PickerListItemView>(base::DoNothing()));
+
+  EXPECT_EQ(section_list.GetItemAbove(item1), nullptr);
+  EXPECT_EQ(section_list.GetItemAbove(item2), nullptr);
+  EXPECT_EQ(section_list.GetItemAbove(item3), item1);
+}
+
+TEST_F(PickerSectionListViewTest, ItemNotInSectionListHasNoItemAbove) {
+  PickerSectionListView section_list(kDefaultSectionWidth);
+  PickerEmojiItemView item_not_in_section_list(base::DoNothing(), u"😊");
+
+  EXPECT_EQ(section_list.GetItemAbove(&item_not_in_section_list), nullptr);
+}
+
+TEST_F(PickerSectionListViewTest, GetsItemBelow) {
+  PickerSectionListView section_list(kDefaultSectionWidth);
+
+  PickerSectionView* section1 = section_list.AddSection();
+  PickerItemView* item1 = section1->AddEmojiItem(
+      std::make_unique<PickerEmojiItemView>(base::DoNothing(), u"😊"));
+  PickerItemView* item2 = section1->AddSymbolItem(
+      std::make_unique<PickerSymbolItemView>(base::DoNothing(), u"♬"));
+  PickerSectionView* section2 = section_list.AddSection();
+  PickerItemView* item3 = section2->AddListItem(
+      std::make_unique<PickerListItemView>(base::DoNothing()));
+
+  EXPECT_EQ(section_list.GetItemBelow(item1), item3);
+  EXPECT_EQ(section_list.GetItemBelow(item2), item3);
+  EXPECT_EQ(section_list.GetItemBelow(item3), nullptr);
+}
+
+TEST_F(PickerSectionListViewTest, ItemNotInSectionListHasNoItemBelow) {
+  PickerSectionListView section_list(kDefaultSectionWidth);
+  PickerEmojiItemView item_not_in_section_list(base::DoNothing(), u"😊");
+
+  EXPECT_EQ(section_list.GetItemBelow(&item_not_in_section_list), nullptr);
+}
+
+TEST_F(PickerSectionListViewTest, GetsItemLeftOf) {
+  PickerSectionListView section_list(kDefaultSectionWidth);
+
+  PickerSectionView* section1 = section_list.AddSection();
+  PickerItemView* item1 = section1->AddEmojiItem(
+      std::make_unique<PickerEmojiItemView>(base::DoNothing(), u"😊"));
+  PickerItemView* item2 = section1->AddSymbolItem(
+      std::make_unique<PickerSymbolItemView>(base::DoNothing(), u"♬"));
+  PickerSectionView* section2 = section_list.AddSection();
+  PickerItemView* item3 = section2->AddListItem(
+      std::make_unique<PickerListItemView>(base::DoNothing()));
+
+  EXPECT_EQ(section_list.GetItemLeftOf(item1), nullptr);
+  EXPECT_EQ(section_list.GetItemLeftOf(item2), item1);
+  EXPECT_EQ(section_list.GetItemLeftOf(item3), nullptr);
+}
+
+TEST_F(PickerSectionListViewTest, ItemNotInSectionListHasNoItemLeftOf) {
+  PickerSectionListView section_list(kDefaultSectionWidth);
+  PickerEmojiItemView item_not_in_section_list(base::DoNothing(), u"😊");
+
+  EXPECT_EQ(section_list.GetItemLeftOf(&item_not_in_section_list), nullptr);
+}
+
+TEST_F(PickerSectionListViewTest, GetsItemRightOf) {
+  PickerSectionListView section_list(kDefaultSectionWidth);
+
+  PickerSectionView* section1 = section_list.AddSection();
+  PickerItemView* item1 = section1->AddEmojiItem(
+      std::make_unique<PickerEmojiItemView>(base::DoNothing(), u"😊"));
+  PickerItemView* item2 = section1->AddSymbolItem(
+      std::make_unique<PickerSymbolItemView>(base::DoNothing(), u"♬"));
+  PickerSectionView* section2 = section_list.AddSection();
+  PickerItemView* item3 = section2->AddListItem(
+      std::make_unique<PickerListItemView>(base::DoNothing()));
+
+  EXPECT_EQ(section_list.GetItemRightOf(item1), item2);
+  EXPECT_EQ(section_list.GetItemRightOf(item2), nullptr);
+  EXPECT_EQ(section_list.GetItemRightOf(item3), nullptr);
+}
+
+TEST_F(PickerSectionListViewTest, ItemNotInSectionListHasNoItemRightOf) {
+  PickerSectionListView section_list(kDefaultSectionWidth);
+  PickerEmojiItemView item_not_in_section_list(base::DoNothing(), u"😊");
+
+  EXPECT_EQ(section_list.GetItemRightOf(&item_not_in_section_list), nullptr);
+}
+
+}  // namespace
+}  // namespace ash
diff --git a/ash/picker/views/picker_section_view.cc b/ash/picker/views/picker_section_view.cc
index 181e95c1..b678cfe7 100644
--- a/ash/picker/views/picker_section_view.cc
+++ b/ash/picker/views/picker_section_view.cc
@@ -18,6 +18,7 @@
 #include "ash/picker/views/picker_list_item_view.h"
 #include "ash/picker/views/picker_small_item_grid_view.h"
 #include "ash/picker/views/picker_symbol_item_view.h"
+#include "ash/picker/views/picker_traversable_item_container.h"
 #include "ash/style/typography.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/chromeos/styles/cros_tokens_color_mappings.h"
@@ -85,43 +86,86 @@
           .Build());
 }
 
-void PickerSectionView::AddListItem(
+PickerListItemView* PickerSectionView::AddListItem(
     std::unique_ptr<PickerListItemView> list_item) {
   if (list_item_container_ == nullptr) {
     list_item_container_ =
         AddChildView(std::make_unique<PickerListItemContainerView>());
   }
-  item_views_.push_back(
-      list_item_container_->AddListItem(std::move(list_item)));
+  PickerListItemView* list_item_ptr =
+      list_item_container_->AddListItem(std::move(list_item));
+  item_views_.push_back(list_item_ptr);
+  return list_item_ptr;
 }
 
-void PickerSectionView::AddEmojiItem(
+PickerEmojiItemView* PickerSectionView::AddEmojiItem(
     std::unique_ptr<PickerEmojiItemView> emoji_item) {
   CreateSmallItemGridIfNeeded();
-  item_views_.push_back(small_item_grid_->AddEmojiItem(std::move(emoji_item)));
+  PickerEmojiItemView* emoji_item_ptr =
+      small_item_grid_->AddEmojiItem(std::move(emoji_item));
+  item_views_.push_back(emoji_item_ptr);
+  return emoji_item_ptr;
 }
 
-void PickerSectionView::AddSymbolItem(
+PickerSymbolItemView* PickerSectionView::AddSymbolItem(
     std::unique_ptr<PickerSymbolItemView> symbol_item) {
   CreateSmallItemGridIfNeeded();
-  item_views_.push_back(
-      small_item_grid_->AddSymbolItem(std::move(symbol_item)));
+  PickerSymbolItemView* symbol_item_ptr =
+      small_item_grid_->AddSymbolItem(std::move(symbol_item));
+  item_views_.push_back(symbol_item_ptr);
+  return symbol_item_ptr;
 }
 
-void PickerSectionView::AddEmoticonItem(
+PickerEmoticonItemView* PickerSectionView::AddEmoticonItem(
     std::unique_ptr<PickerEmoticonItemView> emoticon_item) {
   CreateSmallItemGridIfNeeded();
-  item_views_.push_back(
-      small_item_grid_->AddEmoticonItem(std::move(emoticon_item)));
+  PickerEmoticonItemView* emoticon_item_ptr =
+      small_item_grid_->AddEmoticonItem(std::move(emoticon_item));
+  item_views_.push_back(emoticon_item_ptr);
+  return emoticon_item_ptr;
 }
 
-void PickerSectionView::AddImageItem(
+PickerImageItemView* PickerSectionView::AddImageItem(
     std::unique_ptr<PickerImageItemView> image_item) {
   if (image_item_grid_ == nullptr) {
     image_item_grid_ =
         AddChildView(std::make_unique<PickerImageItemGridView>(section_width_));
   }
-  item_views_.push_back(image_item_grid_->AddImageItem(std::move(image_item)));
+  PickerImageItemView* image_item_ptr =
+      image_item_grid_->AddImageItem(std::move(image_item));
+  item_views_.push_back(image_item_ptr);
+  return image_item_ptr;
+}
+
+PickerItemView* PickerSectionView::GetTopItem() {
+  return GetItemContainer() != nullptr ? GetItemContainer()->GetTopItem()
+                                       : nullptr;
+}
+
+PickerItemView* PickerSectionView::GetBottomItem() {
+  return GetItemContainer() != nullptr ? GetItemContainer()->GetBottomItem()
+                                       : nullptr;
+}
+
+PickerItemView* PickerSectionView::GetItemAbove(PickerItemView* item) {
+  return GetItemContainer() != nullptr ? GetItemContainer()->GetItemAbove(item)
+                                       : nullptr;
+}
+
+PickerItemView* PickerSectionView::GetItemBelow(PickerItemView* item) {
+  return GetItemContainer() != nullptr ? GetItemContainer()->GetItemBelow(item)
+                                       : nullptr;
+}
+
+PickerItemView* PickerSectionView::GetItemLeftOf(PickerItemView* item) {
+  return GetItemContainer() != nullptr ? GetItemContainer()->GetItemLeftOf(item)
+                                       : nullptr;
+}
+
+PickerItemView* PickerSectionView::GetItemRightOf(PickerItemView* item) {
+  return GetItemContainer() != nullptr
+             ? GetItemContainer()->GetItemRightOf(item)
+             : nullptr;
 }
 
 void PickerSectionView::CreateSmallItemGridIfNeeded() {
@@ -131,6 +175,16 @@
   }
 }
 
+PickerTraversableItemContainer* PickerSectionView::GetItemContainer() {
+  if (list_item_container_ != nullptr) {
+    return list_item_container_;
+  } else if (image_item_grid_ != nullptr) {
+    return image_item_grid_;
+  } else {
+    return small_item_grid_;
+  }
+}
+
 BEGIN_METADATA(PickerSectionView)
 END_METADATA
 
diff --git a/ash/picker/views/picker_section_view.h b/ash/picker/views/picker_section_view.h
index a758489..d8d2a419 100644
--- a/ash/picker/views/picker_section_view.h
+++ b/ash/picker/views/picker_section_view.h
@@ -31,6 +31,7 @@
 class PickerListItemView;
 class PickerSmallItemGridView;
 class PickerSymbolItemView;
+class PickerTraversableItemContainer;
 
 // View for a Picker section with a title and related items.
 class ASH_EXPORT PickerSectionView : public views::View {
@@ -48,17 +49,46 @@
 
   // Adds a list item. These are displayed in a vertical list, each item
   // spanning the width of the section.
-  void AddListItem(std::unique_ptr<PickerListItemView> list_item);
+  PickerListItemView* AddListItem(
+      std::unique_ptr<PickerListItemView> list_item);
 
   // Adds a emoji, symbol or emoticon. These are treated collectively as small
   // grid items and are displayed in rows.
-  void AddEmojiItem(std::unique_ptr<PickerEmojiItemView> emoji_item);
-  void AddSymbolItem(std::unique_ptr<PickerSymbolItemView> symbol_item);
-  void AddEmoticonItem(std::unique_ptr<PickerEmoticonItemView> emoticon_item);
+  PickerEmojiItemView* AddEmojiItem(
+      std::unique_ptr<PickerEmojiItemView> emoji_item);
+  PickerSymbolItemView* AddSymbolItem(
+      std::unique_ptr<PickerSymbolItemView> symbol_item);
+  PickerEmoticonItemView* AddEmoticonItem(
+      std::unique_ptr<PickerEmoticonItemView> emoticon_item);
 
   // Adds an image item to the section. These are displayed in a grid with two
   // columns.
-  void AddImageItem(std::unique_ptr<PickerImageItemView> image_item);
+  PickerImageItemView* AddImageItem(
+      std::unique_ptr<PickerImageItemView> image_item);
+
+  // Returns the item to highlight to when navigating to this section from the
+  // top, or nullptr if the section is empty.
+  PickerItemView* GetTopItem();
+
+  // Returns the item to highlight to when navigating to this section from the
+  // bottom, or nullptr if the section is empty.
+  PickerItemView* GetBottomItem();
+
+  // Returns the item directly above `item`, or nullptr if there is no such item
+  // in the section.
+  PickerItemView* GetItemAbove(PickerItemView* item);
+
+  // Returns the item directly below `item`, or nullptr if there is no such item
+  // in the section.
+  PickerItemView* GetItemBelow(PickerItemView* item);
+
+  // Returns the item directly to the left of `item`, or nullptr if there is no
+  // such item in the section.
+  PickerItemView* GetItemLeftOf(PickerItemView* item);
+
+  // Returns the item directly to the right of `item`, or nullptr if there is no
+  // such item in the section.
+  PickerItemView* GetItemRightOf(PickerItemView* item);
 
   const views::Label* title_label_for_testing() const { return title_label_; }
 
@@ -75,6 +105,14 @@
  private:
   void CreateSmallItemGridIfNeeded();
 
+  // Returns a non-null item container if the section has one, otherwise returns
+  // nullptr.
+  // TODO: b/322900302 - Determine whether sections can have multiple item
+  // containers. If so, `GetItemContainer` will need to get the right item
+  // container. If not, just track a single PickerTraversableItemContainer and
+  // then we won't need this method anymore.
+  PickerTraversableItemContainer* GetItemContainer();
+
   // Width available for laying out section items. This is needed to determine
   // row and column widths for grid items in the section.
   int section_width_ = 0;
diff --git a/ash/picker/views/picker_small_item_grid_view.cc b/ash/picker/views/picker_small_item_grid_view.cc
index 2e37182..bfa5463 100644
--- a/ash/picker/views/picker_small_item_grid_view.cc
+++ b/ash/picker/views/picker_small_item_grid_view.cc
@@ -13,6 +13,7 @@
 #include "ash/picker/views/picker_emoticon_item_view.h"
 #include "ash/picker/views/picker_item_view.h"
 #include "ash/picker/views/picker_symbol_item_view.h"
+#include "base/ranges/algorithm.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/size.h"
@@ -64,7 +65,7 @@
     return nullptr;
   }
   // Return the first item in the top row, if it exists.
-  const views::View* row = children().front();
+  views::View* row = children().front();
   return row->children().empty() ? nullptr
                                  : views::AsViewClass<PickerItemView>(
                                        row->children().front().get());
@@ -75,63 +76,56 @@
     return nullptr;
   }
   // Return the first item in the bottom row, if it exists.
-  const views::View* row = children().back();
+  views::View* row = children().back();
   return row->children().empty() ? nullptr
                                  : views::AsViewClass<PickerItemView>(
                                        row->children().front().get());
 }
 
-PickerItemView* PickerSmallItemGridView::GetItemAbove(
-    const PickerItemView* item) {
-  const views::View* row = GetRowContaining(item);
+PickerItemView* PickerSmallItemGridView::GetItemAbove(PickerItemView* item) {
+  views::View* row = GetRowContaining(item);
   if (!row || row == children().front()) {
     return nullptr;
   }
   // Return the first item in the row above, if it exists.
-  const views::View* row_above = std::prev(FindChild(row))->get();
+  views::View* row_above =
+      std::prev(base::ranges::find(children(), row))->get();
   return row_above->children().empty()
              ? nullptr
              : views::AsViewClass<PickerItemView>(
                    row_above->children().front().get());
 }
 
-PickerItemView* PickerSmallItemGridView::GetItemBelow(
-    const PickerItemView* item) {
-  const views::View* row = GetRowContaining(item);
+PickerItemView* PickerSmallItemGridView::GetItemBelow(PickerItemView* item) {
+  views::View* row = GetRowContaining(item);
   if (!row || row == children().back()) {
     return nullptr;
   }
   // Return the first item in the row below, if it exists.
-  const views::View* row_below = std::next(FindChild(row))->get();
+  views::View* row_below =
+      std::next(base::ranges::find(children(), row))->get();
   return row_below->children().empty()
              ? nullptr
              : views::AsViewClass<PickerItemView>(
                    row_below->children().front().get());
 }
 
-PickerItemView* PickerSmallItemGridView::GetItemLeftOf(
-    const PickerItemView* item) {
-  const views::View* row = GetRowContaining(item);
-  if (!row) {
+PickerItemView* PickerSmallItemGridView::GetItemLeftOf(PickerItemView* item) {
+  views::View* row = GetRowContaining(item);
+  if (!row || item == row->children().front()) {
     return nullptr;
   }
-  const views::View::Views::const_iterator it = row->FindChild(item);
-  return it == row->children().cbegin()
-             ? nullptr
-             : views::AsViewClass<PickerItemView>(std::prev(it)->get());
+  return views::AsViewClass<PickerItemView>(
+      std::prev(base::ranges::find(row->children(), item))->get());
 }
 
-PickerItemView* PickerSmallItemGridView::GetItemRightOf(
-    const PickerItemView* item) {
-  const views::View* row = GetRowContaining(item);
-  if (!row) {
+PickerItemView* PickerSmallItemGridView::GetItemRightOf(PickerItemView* item) {
+  views::View* row = GetRowContaining(item);
+  if (!row || item == row->children().back()) {
     return nullptr;
   }
-  const views::View::Views::const_iterator next_it =
-      std::next(row->FindChild(item));
-  return next_it == row->children().cend()
-             ? nullptr
-             : views::AsViewClass<PickerItemView>(next_it->get());
+  return views::AsViewClass<PickerItemView>(
+      std::next(base::ranges::find(row->children(), item))->get());
 }
 
 PickerEmojiItemView* PickerSmallItemGridView::AddEmojiItem(
@@ -172,9 +166,8 @@
   return row->AddChildView(std::move(grid_item));
 }
 
-const views::View* PickerSmallItemGridView::GetRowContaining(
-    const PickerItemView* item) const {
-  const views::View* row = item->parent();
+views::View* PickerSmallItemGridView::GetRowContaining(PickerItemView* item) {
+  views::View* row = item->parent();
   return row && row->parent() == this ? row : nullptr;
 }
 
diff --git a/ash/picker/views/picker_small_item_grid_view.h b/ash/picker/views/picker_small_item_grid_view.h
index 93995f5..4b528bf 100644
--- a/ash/picker/views/picker_small_item_grid_view.h
+++ b/ash/picker/views/picker_small_item_grid_view.h
@@ -35,10 +35,10 @@
   // PickerTraversableItemContainer:
   PickerItemView* GetTopItem() override;
   PickerItemView* GetBottomItem() override;
-  PickerItemView* GetItemAbove(const PickerItemView* item) override;
-  PickerItemView* GetItemBelow(const PickerItemView* item) override;
-  PickerItemView* GetItemLeftOf(const PickerItemView* item) override;
-  PickerItemView* GetItemRightOf(const PickerItemView* item) override;
+  PickerItemView* GetItemAbove(PickerItemView* item) override;
+  PickerItemView* GetItemBelow(PickerItemView* item) override;
+  PickerItemView* GetItemLeftOf(PickerItemView* item) override;
+  PickerItemView* GetItemRightOf(PickerItemView* item) override;
 
   PickerEmojiItemView* AddEmojiItem(
       std::unique_ptr<PickerEmojiItemView> emoji_item);
@@ -53,7 +53,7 @@
 
   // Returns the row containing `item`, or nullptr if `item` is not part of this
   // grid.
-  const views::View* GetRowContaining(const PickerItemView* item) const;
+  views::View* GetRowContaining(PickerItemView* item);
 
   int grid_width_ = 0;
 };
diff --git a/ash/picker/views/picker_strings.cc b/ash/picker/views/picker_strings.cc
index 85e0d96..e18dbd5b 100644
--- a/ash/picker/views/picker_strings.cc
+++ b/ash/picker/views/picker_strings.cc
@@ -87,6 +87,8 @@
       return u"Matching links";
     case PickerSectionType::kFiles:
       return u"Matching files";
+    case PickerSectionType::kDriveFiles:
+      return u"Matching Google Drive files";
     case PickerSectionType::kGifs:
       return u"Other expressions";
     case PickerSectionType::kRecentlyUsed:
diff --git a/ash/picker/views/picker_symbol_item_view.cc b/ash/picker/views/picker_symbol_item_view.cc
index 9fb9833b..eade715 100644
--- a/ash/picker/views/picker_symbol_item_view.cc
+++ b/ash/picker/views/picker_symbol_item_view.cc
@@ -8,12 +8,9 @@
 #include <utility>
 
 #include "ash/picker/views/picker_item_view.h"
-#include "ash/style/style_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/chromeos/styles/cros_tokens_color_mappings.h"
 #include "ui/gfx/font_list.h"
-#include "ui/gfx/geometry/rounded_corners_f.h"
-#include "ui/views/controls/button/button.h"
 #include "ui/views/controls/label.h"
 
 namespace ash {
@@ -25,7 +22,7 @@
                                       kPickerSymbolFontSize,
                                       gfx::Font::Weight::NORMAL);
 
-constexpr auto kPickerSymbolItemCornerRadius = gfx::RoundedCornersF(4);
+constexpr int kPickerSymbolItemCornerRadius = 4;
 
 }  // namespace
 
@@ -34,6 +31,7 @@
     const std::u16string& symbol)
     : PickerItemView(std::move(select_item_callback)) {
   SetUseDefaultFillLayout(true);
+  SetCornerRadius(kPickerSymbolItemCornerRadius);
 
   symbol_label_ =
       AddChildView(views::Builder<views::Label>()
@@ -42,9 +40,6 @@
                        .SetFontList(kPickerSymbolFont)
                        .Build());
   SetAccessibleName(symbol_label_);
-
-  StyleUtil::InstallRoundedCornerHighlightPathGenerator(
-      this, kPickerSymbolItemCornerRadius);
 }
 
 PickerSymbolItemView::~PickerSymbolItemView() = default;
diff --git a/ash/picker/views/picker_traversable_item_container.h b/ash/picker/views/picker_traversable_item_container.h
index 64581d1..f889ea9 100644
--- a/ash/picker/views/picker_traversable_item_container.h
+++ b/ash/picker/views/picker_traversable_item_container.h
@@ -26,19 +26,19 @@
 
   // Returns the item directly above `item`, or nullptr if there is no such item
   // in the container.
-  virtual PickerItemView* GetItemAbove(const PickerItemView* item) = 0;
+  virtual PickerItemView* GetItemAbove(PickerItemView* item) = 0;
 
   // Returns the item directly below `item`, or nullptr if there is no such item
   // in the container.
-  virtual PickerItemView* GetItemBelow(const PickerItemView* item) = 0;
+  virtual PickerItemView* GetItemBelow(PickerItemView* item) = 0;
 
   // Returns the item directly to the left of `item`, or nullptr if there is no
   // such item in the container.
-  virtual PickerItemView* GetItemLeftOf(const PickerItemView* item) = 0;
+  virtual PickerItemView* GetItemLeftOf(PickerItemView* item) = 0;
 
   // Returns the item directly to the right of `item`, or nullptr if there is no
   // such item in the container.
-  virtual PickerItemView* GetItemRightOf(const PickerItemView* item) = 0;
+  virtual PickerItemView* GetItemRightOf(PickerItemView* item) = 0;
 };
 
 }  // namespace ash
diff --git a/ash/picker/views/picker_view.cc b/ash/picker/views/picker_view.cc
index a3a0ca9..11fc9dd 100644
--- a/ash/picker/views/picker_view.cc
+++ b/ash/picker/views/picker_view.cc
@@ -7,7 +7,6 @@
 #include <memory>
 
 #include "ash/ash_element_identifiers.h"
-#include "ash/bubble/bubble_event_filter.h"
 #include "ash/picker/model/picker_search_results_section.h"
 #include "ash/picker/views/picker_category_view.h"
 #include "ash/picker/views/picker_contents_view.h"
@@ -45,7 +44,6 @@
 #include "ui/views/layout/flex_layout.h"
 #include "ui/views/view_class_properties.h"
 #include "ui/views/view_utils.h"
-#include "ui/views/widget/unique_widget_ptr.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/window/non_client_view.h"
 
@@ -58,8 +56,6 @@
 constexpr ui::ColorId kBackgroundColor =
     cros_tokens::kCrosSysSystemBaseElevated;
 
-// Padding to separate the Picker window from the caret.
-constexpr gfx::Outsets kPaddingAroundCaret(4);
 // Padding to separate the Picker window from the screen edge.
 constexpr gfx::Insets kPaddingFromScreenEdge(16);
 
@@ -77,34 +73,6 @@
       .Build();
 }
 
-// Gets the anchor bounds to use for positioning the Picker. We prefer to anchor
-// at `caret_bounds`, but may use `cursor_point` as a fallback. `caret_bounds`,
-// `cursor_point`, `focused_window_bounds` and returned anchor bounds should be
-// in screen coordinates.
-gfx::Rect GetPickerAnchorBounds(const gfx::Rect& caret_bounds,
-                                const gfx::Point& cursor_point,
-                                const gfx::Rect& focused_window_bounds) {
-  if (caret_bounds != gfx::Rect() &&
-      focused_window_bounds.Contains(caret_bounds)) {
-    gfx::Rect anchor_rect = caret_bounds;
-    anchor_rect.Outset(kPaddingAroundCaret);
-    return anchor_rect;
-  } else {
-    return gfx::Rect(cursor_point, gfx::Size());
-  }
-}
-
-// Gets the preferred layout to use given `anchor_bounds` in screen coordinates.
-PickerView::PickerLayoutType GetLayoutType(const gfx::Rect& anchor_bounds) {
-  return anchor_bounds.bottom() + kPickerSize.height() <=
-                 display::Screen::GetScreen()
-                     ->GetDisplayMatching(anchor_bounds)
-                     .work_area()
-                     .bottom()
-             ? PickerView::PickerLayoutType::kResultsBelowSearchField
-             : PickerView::PickerLayoutType::kResultsAboveSearchField;
-}
-
 // Gets the preferred Picker view bounds in screen coordinates. We try to place
 // the Picker view close to `anchor_bounds`, while taking into account
 // `layout_type`, `picker_view_size` and available space on the screen.
@@ -157,8 +125,8 @@
 }  // namespace
 
 PickerView::PickerView(PickerViewDelegate* delegate,
-                       const base::TimeTicks trigger_event_timestamp,
-                       PickerLayoutType layout_type)
+                       PickerLayoutType layout_type,
+                       const base::TimeTicks trigger_event_timestamp)
     : session_metrics_(trigger_event_timestamp), delegate_(delegate) {
   SetShowCloseButton(false);
   SetBackground(views::CreateThemedRoundedRectBackground(kBackgroundColor,
@@ -195,39 +163,6 @@
 
 PickerView::~PickerView() = default;
 
-views::UniqueWidgetPtr PickerView::CreateWidget(
-    const gfx::Rect& caret_bounds,
-    const gfx::Point& cursor_point,
-    const gfx::Rect& focused_window_bounds,
-    PickerViewDelegate* delegate,
-    const base::TimeTicks trigger_event_timestamp) {
-  // Create the Picker view and set its size. This will trigger a layout, so
-  // that the position of the Picker view's search field can be used when
-  // setting the Picker widget bounds below.
-  const gfx::Rect anchor_bounds =
-      GetPickerAnchorBounds(caret_bounds, cursor_point, focused_window_bounds);
-  const PickerLayoutType layout_type = GetLayoutType(anchor_bounds);
-  auto picker_view = std::make_unique<PickerView>(
-      delegate, trigger_event_timestamp, layout_type);
-  picker_view->SetSize(kPickerSize);
-
-  views::Widget::InitParams params;
-  params.activatable = views::Widget::InitParams::Activatable::kYes;
-  params.shadow_type = views::Widget::InitParams::ShadowType::kNone;
-  params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
-  params.type = views::Widget::InitParams::TYPE_BUBBLE;
-  params.z_order = ui::ZOrderLevel::kFloatingUIElement;
-  params.bounds = picker_view->GetTargetBounds(anchor_bounds, layout_type);
-  // TODO(b/309706053): Replace this with the finalized string.
-  params.name = "Picker";
-  params.delegate = picker_view.release();
-
-  auto widget = std::make_unique<views::Widget>(std::move(params));
-  widget->SetVisibilityAnimationTransition(
-      views::Widget::VisibilityTransition::ANIMATE_HIDE);
-  return widget;
-}
-
 bool PickerView::AcceleratorPressed(const ui::Accelerator& accelerator) {
   CHECK_EQ(accelerator.key_code(), ui::VKEY_ESCAPE);
   if (auto* widget = GetWidget()) {
@@ -246,17 +181,10 @@
 
 void PickerView::AddedToWidget() {
   session_metrics_.StartRecording(*GetWidget());
-  // `base::Unretained` is safe here because this class owns
-  // `bubble_event_filter_`.
-  bubble_event_filter_ = std::make_unique<BubbleEventFilter>(
-      GetWidget(), /*button=*/nullptr,
-      base::BindRepeating(&PickerView::OnClickOutsideWidget,
-                          base::Unretained(this)));
 }
 
 void PickerView::RemovedFromWidget() {
   session_metrics_.StopRecording();
-  bubble_event_filter_.reset();
 }
 
 gfx::Rect PickerView::GetTargetBounds(const gfx::Rect& anchor_bounds,
@@ -346,12 +274,6 @@
   category_view_->SetResults(results);
 }
 
-void PickerView::OnClickOutsideWidget(const ui::LocatedEvent& event) {
-  if (auto* widget = GetWidget()) {
-    widget->Close();
-  }
-}
-
 void PickerView::AddSearchFieldView() {
   // `base::Unretained` is safe here because this class owns
   // `search_field_view_`.
@@ -390,7 +312,7 @@
 
 void PickerView::SetActivePage(PickerPageView* page_view) {
   contents_view_->SetActivePage(page_view);
-  key_event_handler_.SetActiveKeyEventTarget(page_view);
+  key_event_handler_.SetActivePseudoFocusHandler(page_view);
 }
 
 BEGIN_METADATA(PickerView)
diff --git a/ash/picker/views/picker_view.h b/ash/picker/views/picker_view.h
index a957a375..a5ec8367 100644
--- a/ash/picker/views/picker_view.h
+++ b/ash/picker/views/picker_view.h
@@ -17,7 +17,6 @@
 #include "base/time/time.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/views/view.h"
-#include "ui/views/widget/unique_widget_ptr.h"
 #include "ui/views/widget/widget_delegate.h"
 
 namespace views {
@@ -27,7 +26,6 @@
 
 namespace ash {
 
-class BubbleEventFilter;
 class PickerContentsView;
 class PickerSearchFieldView;
 class PickerPageView;
@@ -51,25 +49,12 @@
 
   // `delegate` must remain valid for the lifetime of this class.
   explicit PickerView(PickerViewDelegate* delegate,
-                      base::TimeTicks trigger_event_timestamp,
-                      PickerLayoutType layout_type);
+                      PickerLayoutType layout_type,
+                      base::TimeTicks trigger_event_timestamp);
   PickerView(const PickerView&) = delete;
   PickerView& operator=(const PickerView&) = delete;
   ~PickerView() override;
 
-  // `trigger_event_timestamp` is the timestamp of the event that triggered the
-  // Widget to be created. For example, if the feature was triggered by a mouse
-  // click, then it should be the timestamp of the click. By default, the
-  // timestamp is the time this function is called.
-  // `delegate` must remain valid for the lifetime of the created Widget.
-  // `caret_bounds` and `cursor_point` should be in screen coordinates.
-  static views::UniqueWidgetPtr CreateWidget(
-      const gfx::Rect& caret_bounds,
-      const gfx::Point& cursor_point,
-      const gfx::Rect& focused_window_bounds,
-      PickerViewDelegate* delegate,
-      base::TimeTicks trigger_event_timestamp = base::TimeTicks::Now());
-
   // views::WidgetDelegateView:
   bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
   std::unique_ptr<views::NonClientFrameView> CreateNonClientFrameView(
@@ -113,8 +98,6 @@
   // Displays `results` in the category view.
   void PublishCategoryResults(std::vector<PickerSearchResultsSection> results);
 
-  void OnClickOutsideWidget(const ui::LocatedEvent& event);
-
   void AddSearchFieldView();
   void AddContentsView(PickerLayoutType layout_type);
 
@@ -123,9 +106,6 @@
 
   std::optional<PickerCategory> selected_category_;
 
-  // Used to close the Picker widget when the user clicks outside of it.
-  std::unique_ptr<BubbleEventFilter> bubble_event_filter_;
-
   std::unique_ptr<SystemShadow> shadow_;
 
   PickerKeyEventHandler key_event_handler_;
diff --git a/ash/picker/views/picker_view_unittest.cc b/ash/picker/views/picker_view_unittest.cc
index 962fa8c..10ccec6 100644
--- a/ash/picker/views/picker_view_unittest.cc
+++ b/ash/picker/views/picker_view_unittest.cc
@@ -5,6 +5,7 @@
 #include "ash/picker/views/picker_view.h"
 
 #include <optional>
+#include <string>
 
 #include "ash/picker/mock_picker_asset_fetcher.h"
 #include "ash/picker/model/picker_search_results_section.h"
@@ -14,10 +15,13 @@
 #include "ash/picker/views/picker_item_view.h"
 #include "ash/picker/views/picker_search_field_view.h"
 #include "ash/picker/views/picker_search_results_view.h"
+#include "ash/picker/views/picker_section_list_view.h"
 #include "ash/picker/views/picker_section_view.h"
 #include "ash/picker/views/picker_view_delegate.h"
+#include "ash/picker/views/picker_widget.h"
 #include "ash/picker/views/picker_zero_state_view.h"
 #include "ash/public/cpp/picker/picker_category.h"
+#include "ash/public/cpp/picker/picker_search_result.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/test_ash_web_view.h"
@@ -31,6 +35,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/emoji/emoji_panel_helper.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/models/image_model.h"
 #include "ui/chromeos/styles/cros_tokens_color_mappings.h"
 #include "ui/display/screen.h"
 #include "ui/events/event_constants.h"
@@ -42,6 +47,7 @@
 #include "ui/views/controls/scroll_view.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/view_utils.h"
+#include "url/gurl.h"
 
 namespace ash {
 namespace {
@@ -54,9 +60,7 @@
 using ::testing::Property;
 using ::testing::Truly;
 
-constexpr gfx::Rect kDefaultCaretBounds(200, 100, 0, 10);
-constexpr gfx::Point kDefaultCursorPoint(300, 400);
-constexpr gfx::Rect kDefaultFocusedWindowBounds(300, 400);
+constexpr gfx::Rect kDefaultAnchorBounds(200, 100, 0, 10);
 
 class PickerViewTest : public AshTestBase {
  public:
@@ -128,36 +132,9 @@
       ->second->item_views_for_testing()[0];  // Should be open tabs
 }
 
-TEST_F(PickerViewTest, CreateWidgetHasCorrectHierarchy) {
-  FakePickerViewDelegate delegate;
-  auto widget =
-      PickerView::CreateWidget(kDefaultCaretBounds, kDefaultCursorPoint,
-                               kDefaultFocusedWindowBounds, &delegate);
-
-  // Widget should contain a NonClientView, which has a NonClientFrameView for
-  // borders and shadows, and a ClientView with a sole child of the PickerView.
-  ASSERT_TRUE(widget);
-  ASSERT_TRUE(widget->non_client_view());
-  ASSERT_TRUE(widget->non_client_view()->frame_view());
-  ASSERT_TRUE(widget->non_client_view()->client_view());
-  EXPECT_THAT(widget->non_client_view()->client_view()->children(),
-              ElementsAre(Truly(views::IsViewClass<PickerView>)));
-}
-
-TEST_F(PickerViewTest, CreateWidgetHasCorrectBorder) {
-  FakePickerViewDelegate delegate;
-  auto widget =
-      PickerView::CreateWidget(kDefaultCaretBounds, kDefaultCursorPoint,
-                               kDefaultFocusedWindowBounds, &delegate);
-
-  EXPECT_TRUE(widget->non_client_view()->frame_view()->GetBorder());
-}
-
 TEST_F(PickerViewTest, BackgroundIsCorrect) {
   FakePickerViewDelegate delegate;
-  auto widget =
-      PickerView::CreateWidget(kDefaultCaretBounds, kDefaultCursorPoint,
-                               kDefaultFocusedWindowBounds, &delegate);
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
   PickerView* view = GetPickerViewFromWidget(*widget);
 
   ASSERT_TRUE(view);
@@ -169,9 +146,7 @@
 
 TEST_F(PickerViewTest, SizeIsCorrect) {
   FakePickerViewDelegate delegate;
-  auto widget =
-      PickerView::CreateWidget(kDefaultCaretBounds, kDefaultCursorPoint,
-                               kDefaultFocusedWindowBounds, &delegate);
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
   widget->Show();
   PickerView* view = GetPickerViewFromWidget(*widget);
 
@@ -180,9 +155,7 @@
 
 TEST_F(PickerViewTest, ShowsZeroStateView) {
   FakePickerViewDelegate delegate;
-  auto widget =
-      PickerView::CreateWidget(kDefaultCaretBounds, kDefaultCursorPoint,
-                               kDefaultFocusedWindowBounds, &delegate);
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
   PickerView* view = GetPickerViewFromWidget(*widget);
 
   EXPECT_THAT(view->search_field_view_for_testing(),
@@ -195,9 +168,7 @@
 
 TEST_F(PickerViewTest, NonEmptySearchFieldContentsSwitchesToSearchResultsView) {
   FakePickerViewDelegate delegate;
-  auto widget =
-      PickerView::CreateWidget(kDefaultCaretBounds, kDefaultCursorPoint,
-                               kDefaultFocusedWindowBounds, &delegate);
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
   widget->Show();
   PickerView* view = GetPickerViewFromWidget(*widget);
 
@@ -211,9 +182,7 @@
 
 TEST_F(PickerViewTest, EmptySearchFieldContentsSwitchesToZeroStateView) {
   FakePickerViewDelegate delegate;
-  auto widget =
-      PickerView::CreateWidget(kDefaultCaretBounds, kDefaultCursorPoint,
-                               kDefaultFocusedWindowBounds, &delegate);
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
   widget->Show();
   PickerView* view = GetPickerViewFromWidget(*widget);
   PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
@@ -236,9 +205,7 @@
                                        {{PickerSearchResult::Text(u"result")}}),
         });
       }));
-  auto widget =
-      PickerView::CreateWidget(kDefaultCaretBounds, kDefaultCursorPoint,
-                               kDefaultFocusedWindowBounds, &delegate);
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
   widget->Show();
   PickerView* view = GetPickerViewFromWidget(*widget);
   PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
@@ -263,9 +230,7 @@
 
 TEST_F(PickerViewTest, SwitchesToCategoryView) {
   FakePickerViewDelegate delegate;
-  auto widget =
-      PickerView::CreateWidget(kDefaultCaretBounds, kDefaultCursorPoint,
-                               kDefaultFocusedWindowBounds, &delegate);
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
   widget->Show();
 
   PickerView* picker_view = GetPickerViewFromWidget(*widget);
@@ -291,9 +256,7 @@
                                            PickerCategory::kBrowsingHistory)}}),
         });
       }));
-  auto widget =
-      PickerView::CreateWidget(kDefaultCaretBounds, kDefaultCursorPoint,
-                               kDefaultFocusedWindowBounds, &delegate);
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
   widget->Show();
   PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
   ASSERT_TRUE(search_called.Wait());
@@ -313,9 +276,7 @@
 
 TEST_F(PickerViewTest, SelectingCategoryUpdatesSearchFieldPlaceholderText) {
   FakePickerViewDelegate delegate;
-  auto widget =
-      PickerView::CreateWidget(kDefaultCaretBounds, kDefaultCursorPoint,
-                               kDefaultFocusedWindowBounds, &delegate);
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
   widget->Show();
 
   PickerView* picker_view = GetPickerViewFromWidget(*widget);
@@ -334,9 +295,7 @@
 
 TEST_F(PickerViewTest, SearchingWithCategorySwitchesToSearchResultsView) {
   FakePickerViewDelegate delegate;
-  auto widget =
-      PickerView::CreateWidget(kDefaultCaretBounds, kDefaultCursorPoint,
-                               kDefaultFocusedWindowBounds, &delegate);
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
   widget->Show();
 
   // Switch to category view.
@@ -356,9 +315,7 @@
 
 TEST_F(PickerViewTest, EmptySearchFieldSwitchesBackToCategoryView) {
   FakePickerViewDelegate delegate;
-  auto widget =
-      PickerView::CreateWidget(kDefaultCaretBounds, kDefaultCursorPoint,
-                               kDefaultFocusedWindowBounds, &delegate);
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
   widget->Show();
 
   // Switch to category view.
@@ -384,9 +341,7 @@
       [&](FakePickerViewDelegate::SearchResultsCallback callback) {
         search_called.SetValue();
       }));
-  auto widget =
-      PickerView::CreateWidget(kDefaultCaretBounds, kDefaultCursorPoint,
-                               kDefaultFocusedWindowBounds, &delegate);
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
   widget->Show();
 
   PickerView* picker_view = GetPickerViewFromWidget(*widget);
@@ -395,7 +350,9 @@
 
   // Results page should be empty until results arrive.
   EXPECT_TRUE(picker_view->search_results_view_for_testing().GetVisible());
-  EXPECT_THAT(picker_view->search_results_view_for_testing().children(),
+  EXPECT_THAT(picker_view->search_results_view_for_testing()
+                  .section_list_view_for_testing()
+                  ->children(),
               IsEmpty());
 }
 
@@ -407,9 +364,7 @@
         search_callback = std::move(callback);
         search_called.SetValue();
       }));
-  auto widget =
-      PickerView::CreateWidget(kDefaultCaretBounds, kDefaultCursorPoint,
-                               kDefaultFocusedWindowBounds, &delegate);
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
   widget->Show();
 
   PickerView* picker_view = GetPickerViewFromWidget(*widget);
@@ -443,9 +398,7 @@
           search2_called.SetValue();
         }
       }));
-  auto widget =
-      PickerView::CreateWidget(kDefaultCaretBounds, kDefaultCursorPoint,
-                               kDefaultFocusedWindowBounds, &delegate);
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
   widget->Show();
 
   PickerView* picker_view = GetPickerViewFromWidget(*widget);
@@ -482,9 +435,7 @@
           search2_called.SetValue();
         }
       }));
-  auto widget =
-      PickerView::CreateWidget(kDefaultCaretBounds, kDefaultCursorPoint,
-                               kDefaultFocusedWindowBounds, &delegate);
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
   widget->Show();
 
   PickerView* picker_view = GetPickerViewFromWidget(*widget);
@@ -518,9 +469,7 @@
                                        {{PickerSearchResult::Text(u"result")}}),
         });
       }));
-  auto widget =
-      PickerView::CreateWidget(kDefaultCaretBounds, kDefaultCursorPoint,
-                               kDefaultFocusedWindowBounds, &delegate);
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
   widget->Show();
 
   PickerView* picker_view = GetPickerViewFromWidget(*widget);
@@ -531,15 +480,15 @@
   PressAndReleaseKey(ui::KeyboardCode::VKEY_BACK, ui::EF_NONE);
 
   EXPECT_FALSE(picker_view->search_results_view_for_testing().GetVisible());
-  EXPECT_THAT(picker_view->search_results_view_for_testing().children(),
+  EXPECT_THAT(picker_view->search_results_view_for_testing()
+                  .section_list_view_for_testing()
+                  ->children(),
               IsEmpty());
 }
 
 TEST_F(PickerViewTest, PressingEscClosesPickerWidget) {
   FakePickerViewDelegate delegate;
-  auto widget =
-      PickerView::CreateWidget(kDefaultCaretBounds, kDefaultCursorPoint,
-                               kDefaultFocusedWindowBounds, &delegate);
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
   widget->Show();
 
   PressAndReleaseKey(ui::KeyboardCode::VKEY_ESCAPE, ui::EF_NONE);
@@ -547,21 +496,6 @@
   EXPECT_TRUE(widget->IsClosed());
 }
 
-TEST_F(PickerViewTest, ClickingOutsideClosesPickerWidget) {
-  FakePickerViewDelegate delegate;
-  auto widget =
-      PickerView::CreateWidget(kDefaultCaretBounds, kDefaultCursorPoint,
-                               kDefaultFocusedWindowBounds, &delegate);
-  widget->Show();
-
-  gfx::Point point_outside_widget = widget->GetWindowBoundsInScreen().origin();
-  point_outside_widget.Offset(-10, -10);
-  GetEventGenerator()->MoveMouseTo(point_outside_widget);
-  GetEventGenerator()->ClickLeftButton();
-
-  EXPECT_TRUE(widget->IsClosed());
-}
-
 TEST_F(PickerViewTest, RecordsSearchLatencyAfterSearchFinished) {
   base::HistogramTester histogram;
   FakePickerViewDelegate delegate(base::BindLambdaForTesting(
@@ -569,9 +503,7 @@
         task_environment()->FastForwardBy(base::Seconds(1));
         callback.Run({});
       }));
-  auto widget =
-      PickerView::CreateWidget(kDefaultCaretBounds, kDefaultCursorPoint,
-                               kDefaultFocusedWindowBounds, &delegate);
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
   widget->Show();
 
   PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
@@ -580,162 +512,110 @@
                                    base::Seconds(1), 1);
 }
 
-TEST_F(PickerViewTest, BoundsDefaultAlignedWithCaret) {
+TEST_F(PickerViewTest, BoundsDefaultAlignedWithAnchor) {
   FakePickerViewDelegate delegate;
-  auto widget =
-      PickerView::CreateWidget(kDefaultCaretBounds, kDefaultCursorPoint,
-                               kDefaultFocusedWindowBounds, &delegate);
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
   widget->Show();
 
   PickerView* view = GetPickerViewFromWidget(*widget);
   // Should be entirely on screen.
   EXPECT_TRUE(display::Screen::GetScreen()
-                  ->GetDisplayMatching(kDefaultCaretBounds)
+                  ->GetDisplayMatching(kDefaultAnchorBounds)
                   .work_area()
                   .Contains(view->GetBoundsInScreen()));
-  // Should be to the right of the caret.
-  EXPECT_GT(view->GetBoundsInScreen().x(), kDefaultCaretBounds.right());
-  // Center of the search field should be vertically aligned with the caret.
+  // Should be to the right of the anchor.
+  EXPECT_EQ(view->GetBoundsInScreen().x(), kDefaultAnchorBounds.right());
+  // Center of the search field should be vertically aligned with the anchor.
   EXPECT_EQ(view->search_field_view_for_testing()
                 .GetBoundsInScreen()
                 .CenterPoint()
                 .y(),
-            kDefaultCaretBounds.CenterPoint().y());
+            kDefaultAnchorBounds.CenterPoint().y());
 }
 
-TEST_F(PickerViewTest, BoundsAlignedWithCaretNearTopLeftOfScreen) {
+TEST_F(PickerViewTest, BoundsAlignedWithAnchorNearTopLeftOfScreen) {
   FakePickerViewDelegate delegate;
   const gfx::Rect screen_work_area =
       display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
-  gfx::Rect caret_bounds(screen_work_area.origin(), {0, 10});
-  caret_bounds.Offset(80, 80);
+  gfx::Rect anchor_bounds(screen_work_area.origin(), {0, 10});
+  anchor_bounds.Offset(80, 80);
 
-  auto widget = PickerView::CreateWidget(caret_bounds, kDefaultCursorPoint,
-                                         screen_work_area, &delegate);
+  auto widget = PickerWidget::Create(&delegate, anchor_bounds);
   widget->Show();
 
   PickerView* view = GetPickerViewFromWidget(*widget);
   // Should be entirely on screen.
   EXPECT_TRUE(screen_work_area.Contains(view->GetBoundsInScreen()));
-  // Should be to the right of the caret.
-  EXPECT_GT(view->GetBoundsInScreen().x(), caret_bounds.right());
-  // Center of the search field should be vertically aligned with the caret.
+  // Should be to the right of the anchor.
+  EXPECT_EQ(view->GetBoundsInScreen().x(), anchor_bounds.right());
+  // Center of the search field should be vertically aligned with the anchor.
   EXPECT_EQ(view->search_field_view_for_testing()
                 .GetBoundsInScreen()
                 .CenterPoint()
                 .y(),
-            caret_bounds.CenterPoint().y());
+            anchor_bounds.CenterPoint().y());
 }
 
-TEST_F(PickerViewTest, BoundsAlignedWithCaretNearBottomLeftOfScreen) {
+TEST_F(PickerViewTest, BoundsAlignedWithAnchorNearBottomLeftOfScreen) {
   FakePickerViewDelegate delegate;
   const gfx::Rect screen_work_area =
       display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
-  gfx::Rect caret_bounds(screen_work_area.bottom_left(), {0, 10});
-  caret_bounds.Offset(80, -80);
+  gfx::Rect anchor_bounds(screen_work_area.bottom_left(), {0, 10});
+  anchor_bounds.Offset(80, -80);
 
-  auto widget = PickerView::CreateWidget(caret_bounds, kDefaultCursorPoint,
-                                         screen_work_area, &delegate);
+  auto widget = PickerWidget::Create(&delegate, anchor_bounds);
   widget->Show();
 
   PickerView* view = GetPickerViewFromWidget(*widget);
   // Should be entirely on screen.
   EXPECT_TRUE(screen_work_area.Contains(view->GetBoundsInScreen()));
-  // Should be to the right of the caret.
-  EXPECT_GT(view->GetBoundsInScreen().x(), caret_bounds.right());
-  // Center of the search field should be vertically aligned with the caret.
+  // Should be to the right of the anchor.
+  EXPECT_EQ(view->GetBoundsInScreen().x(), anchor_bounds.right());
+  // Center of the search field should be vertically aligned with the anchor.
   EXPECT_EQ(view->search_field_view_for_testing()
                 .GetBoundsInScreen()
                 .CenterPoint()
                 .y(),
-            caret_bounds.CenterPoint().y());
+            anchor_bounds.CenterPoint().y());
 }
 
-TEST_F(PickerViewTest, BoundsBelowCaretForCaretNearTopRightOfScreen) {
+TEST_F(PickerViewTest, BoundsBelowAnchorForAnchorNearTopRightOfScreen) {
   FakePickerViewDelegate delegate;
   const gfx::Rect screen_work_area =
       display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
-  gfx::Rect caret_bounds(screen_work_area.top_right(), {0, 10});
-  caret_bounds.Offset(-20, 20);
+  gfx::Rect anchor_bounds(screen_work_area.top_right(), {0, 10});
+  anchor_bounds.Offset(-20, 20);
 
-  auto widget = PickerView::CreateWidget(caret_bounds, kDefaultCursorPoint,
-                                         screen_work_area, &delegate);
+  auto widget = PickerWidget::Create(&delegate, anchor_bounds);
   widget->Show();
 
   const PickerView* view = GetPickerViewFromWidget(*widget);
   // Should be entirely on screen.
   EXPECT_TRUE(screen_work_area.Contains(view->GetBoundsInScreen()));
-  // Should be below the caret.
-  EXPECT_GT(view->GetBoundsInScreen().y(), caret_bounds.bottom());
+  // Should be below the anchor.
+  EXPECT_EQ(view->GetBoundsInScreen().y(), anchor_bounds.bottom());
 }
 
-TEST_F(PickerViewTest, BoundsAboveCaretForCaretNearBottomRightOfScreen) {
+TEST_F(PickerViewTest, BoundsAboveAnchorForAnchorNearBottomRightOfScreen) {
   FakePickerViewDelegate delegate;
   const gfx::Rect screen_work_area =
       display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
-  gfx::Rect caret_bounds(screen_work_area.bottom_right(), {0, 10});
-  caret_bounds.Offset(-20, -20);
+  gfx::Rect anchor_bounds(screen_work_area.bottom_right(), {0, 10});
+  anchor_bounds.Offset(-20, -20);
 
-  auto widget = PickerView::CreateWidget(caret_bounds, kDefaultCursorPoint,
-                                         screen_work_area, &delegate);
+  auto widget = PickerWidget::Create(&delegate, anchor_bounds);
   widget->Show();
 
   const PickerView* view = GetPickerViewFromWidget(*widget);
   // Should be entirely on screen.
   EXPECT_TRUE(screen_work_area.Contains(view->GetBoundsInScreen()));
-  // Should be above the caret.
-  EXPECT_LT(view->GetBoundsInScreen().bottom(), caret_bounds.y());
+  // Should be above the anchor.
+  EXPECT_EQ(view->GetBoundsInScreen().bottom(), anchor_bounds.y());
 }
 
-TEST_F(PickerViewTest, BoundsAlignedWithCursorForEmptyCaretBounds) {
+TEST_F(PickerViewTest, BoundsOnScreenForEmptyAnchorBounds) {
   FakePickerViewDelegate delegate;
-  auto widget = PickerView::CreateWidget(
-      gfx::Rect(), kDefaultCursorPoint, kDefaultFocusedWindowBounds, &delegate);
-  widget->Show();
-
-  PickerView* view = GetPickerViewFromWidget(*widget);
-  // Should be entirely on screen.
-  EXPECT_TRUE(display::Screen::GetScreen()
-                  ->GetDisplayNearestPoint(kDefaultCursorPoint)
-                  .work_area()
-                  .Contains(view->GetBoundsInScreen()));
-  // Should be to the right of the cursor.
-  EXPECT_GE(view->GetBoundsInScreen().x(), kDefaultCursorPoint.x());
-  // Center of the search field should be vertically aligned with the cursor.
-  EXPECT_EQ(view->search_field_view_for_testing()
-                .GetBoundsInScreen()
-                .CenterPoint()
-                .y(),
-            kDefaultCursorPoint.y());
-}
-
-TEST_F(PickerViewTest, BoundsAlignedWithCursorForCaretOutsideFocusedWindow) {
-  FakePickerViewDelegate delegate;
-  auto widget = PickerView::CreateWidget(
-      /*caret_bounds=*/gfx::Rect(10, 10, 0, 10), kDefaultCursorPoint,
-      /*focused_window_bounds=*/gfx::Rect(100, 100, 300, 300), &delegate);
-  widget->Show();
-
-  PickerView* view = GetPickerViewFromWidget(*widget);
-  // Should be entirely on screen.
-  EXPECT_TRUE(display::Screen::GetScreen()
-                  ->GetDisplayNearestPoint(kDefaultCursorPoint)
-                  .work_area()
-                  .Contains(view->GetBoundsInScreen()));
-  // Should be to the right of the cursor.
-  EXPECT_GE(view->GetBoundsInScreen().x(), kDefaultCursorPoint.x());
-  // Center of the search field should be vertically aligned with the cursor.
-  EXPECT_EQ(view->search_field_view_for_testing()
-                .GetBoundsInScreen()
-                .CenterPoint()
-                .y(),
-            kDefaultCursorPoint.y());
-}
-
-TEST_F(PickerViewTest, BoundsOnScreenForEmptyCaretAndEmptyCursor) {
-  FakePickerViewDelegate delegate;
-  auto widget = PickerView::CreateWidget(
-      gfx::Rect(), gfx::Point(), kDefaultFocusedWindowBounds, &delegate);
+  auto widget = PickerWidget::Create(&delegate, gfx::Rect());
   widget->Show();
 
   const PickerView* view = GetPickerViewFromWidget(*widget);
@@ -748,11 +628,10 @@
   FakePickerViewDelegate delegate;
   const gfx::Rect screen_work_area =
       display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
-  gfx::Rect caret_bounds(screen_work_area.top_center(), {0, 10});
-  caret_bounds.Offset(0, 80);
+  gfx::Rect anchor_bounds(screen_work_area.top_center(), {0, 10});
+  anchor_bounds.Offset(0, 80);
 
-  auto widget = PickerView::CreateWidget(caret_bounds, kDefaultCursorPoint,
-                                         screen_work_area, &delegate);
+  auto widget = PickerWidget::Create(&delegate, anchor_bounds);
   widget->Show();
 
   PickerView* view = GetPickerViewFromWidget(*widget);
@@ -764,11 +643,10 @@
   FakePickerViewDelegate delegate;
   const gfx::Rect screen_work_area =
       display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
-  gfx::Rect caret_bounds(screen_work_area.bottom_center(), {0, 10});
-  caret_bounds.Offset(0, -80);
+  gfx::Rect anchor_bounds(screen_work_area.bottom_center(), {0, 10});
+  anchor_bounds.Offset(0, -80);
 
-  auto widget = PickerView::CreateWidget(caret_bounds, kDefaultCursorPoint,
-                                         screen_work_area, &delegate);
+  auto widget = PickerWidget::Create(&delegate, anchor_bounds);
   widget->Show();
 
   PickerView* view = GetPickerViewFromWidget(*widget);
@@ -778,9 +656,7 @@
 
 TEST_F(PickerViewTest, ShowsEmojiPickerWhenClickingOnEmoji) {
   FakePickerViewDelegate delegate;
-  auto widget =
-      PickerView::CreateWidget(kDefaultCaretBounds, kDefaultCursorPoint,
-                               kDefaultFocusedWindowBounds, &delegate);
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
   widget->Show();
   bool called = false;
   ui::SetShowEmojiKeyboardCallback(base::BindLambdaForTesting(
@@ -801,9 +677,7 @@
             PickerSearchResultsSection(PickerSectionType::kExpressions, {}),
         });
       }));
-  auto widget =
-      PickerView::CreateWidget(kDefaultCaretBounds, kDefaultCursorPoint,
-                               kDefaultFocusedWindowBounds, &delegate);
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
   widget->Show();
   PickerView* view = GetPickerViewFromWidget(*widget);
   PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
@@ -814,26 +688,73 @@
   EXPECT_EQ(delegate.last_inserted_result(), std::nullopt);
 }
 
-TEST_F(PickerViewTest, PressingEnterSelectsSearchResult) {
+TEST_F(PickerViewTest, PressingEnterDefaultSelectsFirstSearchResult) {
   base::test::TestFuture<void> future;
   FakePickerViewDelegate delegate(base::BindLambdaForTesting(
       [&](FakePickerViewDelegate::SearchResultsCallback callback) {
         future.SetValue();
         callback.Run({
             PickerSearchResultsSection(PickerSectionType::kExpressions,
-                                       {{PickerSearchResult::Text(u"result")}}),
+                                       {{PickerSearchResult::Emoji(u"😊"),
+                                         PickerSearchResult::Symbol(u"♬")}}),
         });
       }));
-  auto widget =
-      PickerView::CreateWidget(kDefaultCaretBounds, kDefaultCursorPoint,
-                               kDefaultFocusedWindowBounds, &delegate);
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
   widget->Show();
   PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
   ASSERT_TRUE(future.Wait());
   PressAndReleaseKey(ui::KeyboardCode::VKEY_RETURN, ui::EF_NONE);
 
   EXPECT_THAT(delegate.last_inserted_result(),
-              Optional(PickerSearchResult::Text(u"result")));
+              Optional(PickerSearchResult::Emoji(u"😊")));
+}
+
+TEST_F(PickerViewTest, RightArrowKeyNavigatesSearchResults) {
+  base::test::TestFuture<void> future;
+  FakePickerViewDelegate delegate(base::BindLambdaForTesting(
+      [&](FakePickerViewDelegate::SearchResultsCallback callback) {
+        future.SetValue();
+        callback.Run({
+            PickerSearchResultsSection(PickerSectionType::kExpressions,
+                                       {{PickerSearchResult::Emoji(u"😊"),
+                                         PickerSearchResult::Symbol(u"♬")}}),
+        });
+      }));
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
+  widget->Show();
+  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
+  ASSERT_TRUE(future.Wait());
+  PressAndReleaseKey(ui::KeyboardCode::VKEY_RIGHT, ui::EF_NONE);
+  PressAndReleaseKey(ui::KeyboardCode::VKEY_RETURN, ui::EF_NONE);
+
+  EXPECT_THAT(delegate.last_inserted_result(),
+              Optional(PickerSearchResult::Symbol(u"♬")));
+}
+
+TEST_F(PickerViewTest, DownArrowKeyNavigatesSearchResults) {
+  base::test::TestFuture<void> future;
+  FakePickerViewDelegate delegate(base::BindLambdaForTesting(
+      [&](FakePickerViewDelegate::SearchResultsCallback callback) {
+        future.SetValue();
+        callback.Run({
+            PickerSearchResultsSection(
+                PickerSectionType::kCategories,
+                {{PickerSearchResult::BrowsingHistory(GURL("http://foo.com"),
+                                                      u"Foo", ui::ImageModel()),
+                  PickerSearchResult::BrowsingHistory(
+                      GURL("http://bar.com"), u"Bar", ui::ImageModel())}}),
+        });
+      }));
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
+  widget->Show();
+  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
+  ASSERT_TRUE(future.Wait());
+  PressAndReleaseKey(ui::KeyboardCode::VKEY_DOWN, ui::EF_NONE);
+  PressAndReleaseKey(ui::KeyboardCode::VKEY_RETURN, ui::EF_NONE);
+
+  EXPECT_THAT(delegate.last_inserted_result(),
+              Optional(PickerSearchResult::BrowsingHistory(
+                  GURL("http://bar.com"), u"Bar", ui::ImageModel())));
 }
 
 }  // namespace
diff --git a/ash/picker/views/picker_widget.cc b/ash/picker/views/picker_widget.cc
new file mode 100644
index 0000000..5fb981e
--- /dev/null
+++ b/ash/picker/views/picker_widget.cc
@@ -0,0 +1,90 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/picker/views/picker_widget.h"
+
+#include "ash/bubble/bubble_event_filter.h"
+#include "ash/picker/views/picker_view.h"
+#include "base/functional/bind.h"
+#include "base/memory/ptr_util.h"
+#include "ui/display/screen.h"
+#include "ui/events/event.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/views/view_utils.h"
+#include "ui/views/widget/unique_widget_ptr.h"
+#include "ui/views/widget/widget.h"
+
+namespace ash {
+namespace {
+
+constexpr gfx::Size kPickerSize(320, 340);
+
+// Gets the preferred layout to use given `anchor_bounds` in screen coordinates.
+PickerView::PickerLayoutType GetLayoutType(const gfx::Rect& anchor_bounds) {
+  return anchor_bounds.bottom() + kPickerSize.height() <=
+                 display::Screen::GetScreen()
+                     ->GetDisplayMatching(anchor_bounds)
+                     .work_area()
+                     .bottom()
+             ? PickerView::PickerLayoutType::kResultsBelowSearchField
+             : PickerView::PickerLayoutType::kResultsAboveSearchField;
+}
+
+views::Widget::InitParams CreateInitParams(
+    PickerViewDelegate* delegate,
+    const gfx::Rect& anchor_bounds,
+    const base::TimeTicks trigger_event_timestamp) {
+  const PickerView::PickerLayoutType layout_type = GetLayoutType(anchor_bounds);
+  auto picker_view = std::make_unique<PickerView>(delegate, layout_type,
+                                                  trigger_event_timestamp);
+  picker_view->SetSize(kPickerSize);
+
+  views::Widget::InitParams params;
+  params.activatable = views::Widget::InitParams::Activatable::kYes;
+  params.shadow_type = views::Widget::InitParams::ShadowType::kNone;
+  params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
+  params.type = views::Widget::InitParams::TYPE_BUBBLE;
+  params.z_order = ui::ZOrderLevel::kFloatingUIElement;
+  params.bounds = picker_view->GetTargetBounds(anchor_bounds, layout_type);
+  // TODO(b/309706053): Replace this with the finalized string.
+  params.name = "Picker";
+  params.delegate = picker_view.release();
+  return params;
+}
+
+}  // namespace
+
+views::UniqueWidgetPtr PickerWidget::Create(
+    PickerViewDelegate* delegate,
+    const gfx::Rect& anchor_bounds,
+    base::TimeTicks trigger_event_timestamp) {
+  return base::WrapUnique(
+      new PickerWidget(delegate, anchor_bounds, trigger_event_timestamp));
+}
+
+PickerWidget::PickerWidget(PickerViewDelegate* delegate,
+                           const gfx::Rect& anchor_bounds,
+                           base::TimeTicks trigger_event_timestamp)
+    : views::Widget(
+          CreateInitParams(delegate, anchor_bounds, trigger_event_timestamp)),
+      bubble_event_filter_(
+          /*widget=*/this,
+          /*button=*/nullptr,
+          // base::Unretained is safe here because this class owns
+          // `bubble_event_filter_.
+          base::BindRepeating(&PickerWidget::OnClickOutsideWidget,
+                              base::Unretained(this))) {
+  SetVisibilityAnimationTransition(
+      views::Widget::VisibilityTransition::ANIMATE_HIDE);
+}
+
+void PickerWidget::OnClickOutsideWidget(const ui::LocatedEvent& event) {
+  Close();
+}
+
+PickerWidget::~PickerWidget() = default;
+
+}  // namespace ash
diff --git a/ash/picker/views/picker_widget.h b/ash/picker/views/picker_widget.h
new file mode 100644
index 0000000..a26ed95
--- /dev/null
+++ b/ash/picker/views/picker_widget.h
@@ -0,0 +1,55 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_PICKER_VIEWS_PICKER_WIDGET_H_
+#define ASH_PICKER_VIEWS_PICKER_WIDGET_H_
+
+#include "ash/ash_export.h"
+#include "ash/bubble/bubble_event_filter.h"
+#include "base/time/time.h"
+#include "ui/views/widget/unique_widget_ptr.h"
+#include "ui/views/widget/widget.h"
+
+namespace gfx {
+class Rect;
+}  // namespace gfx
+
+namespace ui {
+class LocatedEvent;
+}
+
+namespace ash {
+class PickerViewDelegate;
+
+class ASH_EXPORT PickerWidget : public views::Widget {
+ public:
+  PickerWidget(const PickerWidget&) = delete;
+  PickerWidget& operator=(const PickerWidget&) = delete;
+  ~PickerWidget() override;
+
+  // `delegate` must remain valid for the lifetime of the created Widget.
+  // `anchor_bounds` is in screen coordinates.
+  // `trigger_event_timestamp` is the timestamp of the event that triggered the
+  // Widget to be created. For example, if the feature was triggered by a mouse
+  // click, then it should be the timestamp of the click. By default, the
+  // timestamp is the time this function is called.
+  static views::UniqueWidgetPtr Create(
+      PickerViewDelegate* delegate,
+      const gfx::Rect& anchor_bounds,
+      base::TimeTicks trigger_event_timestamp = base::TimeTicks::Now());
+
+ private:
+  explicit PickerWidget(PickerViewDelegate* delegate,
+                        const gfx::Rect& anchor_bounds,
+                        base::TimeTicks trigger_event_timestamp);
+
+  void OnClickOutsideWidget(const ui::LocatedEvent& event);
+
+  // Used to close the Picker widget when the user clicks outside of it.
+  BubbleEventFilter bubble_event_filter_;
+};
+
+}  // namespace ash
+
+#endif  // ASH_PICKER_VIEWS_PICKER_VIEW_H_
diff --git a/ash/picker/views/picker_widget_unittest.cc b/ash/picker/views/picker_widget_unittest.cc
new file mode 100644
index 0000000..1cb7a73
--- /dev/null
+++ b/ash/picker/views/picker_widget_unittest.cc
@@ -0,0 +1,81 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/picker/views/picker_widget.h"
+
+#include <memory>
+
+#include "ash/picker/views/picker_view.h"
+#include "ash/picker/views/picker_view_delegate.h"
+#include "ash/test/ash_test_base.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/test/event_generator.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/views/view_utils.h"
+#include "ui/views/widget/widget_utils.h"
+
+namespace ash {
+namespace {
+
+using ::testing::ElementsAre;
+using ::testing::Truly;
+
+constexpr gfx::Rect kDefaultAnchorBounds(200, 100, 0, 10);
+
+class FakePickerViewDelegate : public PickerViewDelegate {
+ public:
+  // PickerViewDelegate:
+  std::unique_ptr<AshWebView> CreateWebView(
+      const AshWebView::InitParams& params) override {
+    return nullptr;
+  }
+  void GetResultsForCategory(PickerCategory category,
+                             SearchResultsCallback callback) override {}
+  void StartSearch(const std::u16string& query,
+                   std::optional<PickerCategory> category,
+                   SearchResultsCallback callback) override {}
+  void InsertResultOnNextFocus(const PickerSearchResult& result) override {}
+  PickerAssetFetcher* GetAssetFetcher() override { return nullptr; }
+};
+
+using PickerWidgetTest = AshTestBase;
+
+TEST_F(PickerWidgetTest, CreateWidgetHasCorrectHierarchy) {
+  FakePickerViewDelegate delegate;
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
+
+  // Widget should contain a NonClientView, which has a NonClientFrameView for
+  // borders and shadows, and a ClientView with a sole child of the PickerView.
+  ASSERT_TRUE(widget);
+  ASSERT_TRUE(widget->non_client_view());
+  ASSERT_TRUE(widget->non_client_view()->frame_view());
+  ASSERT_TRUE(widget->non_client_view()->client_view());
+  EXPECT_THAT(widget->non_client_view()->client_view()->children(),
+              ElementsAre(Truly(views::IsViewClass<PickerView>)));
+}
+
+TEST_F(PickerWidgetTest, CreateWidgetHasCorrectBorder) {
+  FakePickerViewDelegate delegate;
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
+
+  EXPECT_TRUE(widget->non_client_view()->frame_view()->GetBorder());
+}
+
+TEST_F(PickerWidgetTest, ClickingOutsideClosesPickerWidget) {
+  FakePickerViewDelegate delegate;
+  auto widget = PickerWidget::Create(&delegate, kDefaultAnchorBounds);
+  widget->Show();
+
+  gfx::Point point_outside_widget = widget->GetWindowBoundsInScreen().origin();
+  point_outside_widget.Offset(-10, -10);
+  GetEventGenerator()->MoveMouseTo(point_outside_widget);
+  GetEventGenerator()->ClickLeftButton();
+
+  EXPECT_TRUE(widget->IsClosed());
+}
+
+}  // namespace
+}  // namespace ash
diff --git a/ash/picker/views/picker_zero_state_view.cc b/ash/picker/views/picker_zero_state_view.cc
index f303995..0c04263 100644
--- a/ash/picker/views/picker_zero_state_view.cc
+++ b/ash/picker/views/picker_zero_state_view.cc
@@ -15,6 +15,7 @@
 #include "ash/picker/views/picker_category_type.h"
 #include "ash/picker/views/picker_icons.h"
 #include "ash/picker/views/picker_list_item_view.h"
+#include "ash/picker/views/picker_section_list_view.h"
 #include "ash/picker/views/picker_section_view.h"
 #include "ash/picker/views/picker_strings.h"
 #include "ash/public/cpp/picker/picker_category.h"
@@ -30,13 +31,14 @@
 
 PickerZeroStateView::PickerZeroStateView(
     int picker_view_width,
-    SelectCategoryCallback select_category_callback)
-    : picker_view_width_(picker_view_width) {
+    SelectCategoryCallback select_category_callback) {
   SetLayoutManager(std::make_unique<views::FlexLayout>())
       ->SetOrientation(views::LayoutOrientation::kVertical);
 
   AddChildView(std::make_unique<PickerCapsNudgeView>());
 
+  section_list_view_ =
+      AddChildView(std::make_unique<PickerSectionListView>(picker_view_width));
   for (auto category : PickerModel().GetAvailableCategories()) {
     auto item_view = std::make_unique<PickerListItemView>(
         base::BindRepeating(select_category_callback, category));
@@ -44,14 +46,74 @@
     item_view->SetLeadingIcon(GetIconForPickerCategory(category));
     GetOrCreateSectionView(category)->AddListItem(std::move(item_view));
   }
+  SetPseudoFocusedItem(section_list_view_->GetTopItem());
 }
 
 PickerZeroStateView::~PickerZeroStateView() = default;
 
-bool PickerZeroStateView::OnEnterKeyPressed() {
-  // TODO: b/322900302 - Select the highlighted item or a smart suggestion when
-  // enter key is pressed.
-  return false;
+bool PickerZeroStateView::DoPseudoFocusedAction() {
+  if (pseudo_focused_item_ == nullptr) {
+    return false;
+  }
+
+  pseudo_focused_item_->SelectItem();
+  return true;
+}
+
+bool PickerZeroStateView::MovePseudoFocusUp() {
+  if (pseudo_focused_item_ == nullptr) {
+    return false;
+  }
+
+  PickerItemView* item = section_list_view_->GetItemAbove(pseudo_focused_item_);
+  if (item == nullptr) {
+    // If there's no item above, move pseudo focus to the bottom item.
+    item = section_list_view_->GetBottomItem();
+  }
+  SetPseudoFocusedItem(item);
+  return true;
+}
+
+bool PickerZeroStateView::MovePseudoFocusDown() {
+  if (pseudo_focused_item_ == nullptr) {
+    return false;
+  }
+
+  PickerItemView* item = section_list_view_->GetItemBelow(pseudo_focused_item_);
+  if (item == nullptr) {
+    // If there's no item below, move pseudo focus to the top item.
+    item = section_list_view_->GetTopItem();
+  }
+  SetPseudoFocusedItem(item);
+  return true;
+}
+
+bool PickerZeroStateView::MovePseudoFocusLeft() {
+  if (pseudo_focused_item_ == nullptr) {
+    return false;
+  }
+
+  PickerItemView* item =
+      section_list_view_->GetItemLeftOf(pseudo_focused_item_);
+  if (item == nullptr) {
+    return false;
+  }
+  SetPseudoFocusedItem(item);
+  return true;
+}
+
+bool PickerZeroStateView::MovePseudoFocusRight() {
+  if (pseudo_focused_item_ == nullptr) {
+    return false;
+  }
+
+  PickerItemView* item =
+      section_list_view_->GetItemRightOf(pseudo_focused_item_);
+  if (item == nullptr) {
+    return false;
+  }
+  SetPseudoFocusedItem(item);
+  return true;
 }
 
 PickerSectionView* PickerZeroStateView::GetOrCreateSectionView(
@@ -62,14 +124,51 @@
     return section_view_iterator->second;
   }
 
-  auto* section_view =
-      AddChildView(std::make_unique<PickerSectionView>(picker_view_width_));
+  auto* section_view = section_list_view_->AddSection();
   section_view->AddTitleLabel(
       GetSectionTitleForPickerCategoryType(category_type));
   section_views_.insert({category_type, section_view});
   return section_view;
 }
 
+void PickerZeroStateView::SetPseudoFocusedItem(PickerItemView* item) {
+  if (pseudo_focused_item_ == item) {
+    return;
+  }
+
+  if (pseudo_focused_item_ != nullptr) {
+    pseudo_focused_item_->SetItemState(PickerItemView::ItemState::kNormal);
+  }
+
+  pseudo_focused_item_ = item;
+
+  if (pseudo_focused_item_ != nullptr) {
+    pseudo_focused_item_->SetItemState(
+        PickerItemView::ItemState::kPseudoFocused);
+    ScrollPseudoFocusedItemToVisible();
+  }
+}
+
+void PickerZeroStateView::ScrollPseudoFocusedItemToVisible() {
+  if (pseudo_focused_item_ == nullptr) {
+    return;
+  }
+
+  if (section_list_view_->GetItemAbove(pseudo_focused_item_) == nullptr) {
+    // For items at the top, scroll all the way up to let users see that they
+    // have reached the top of the zero state view.
+    ScrollRectToVisible(gfx::Rect(GetLocalBounds().origin(), gfx::Size()));
+  } else if (section_list_view_->GetItemBelow(pseudo_focused_item_) ==
+             nullptr) {
+    // For items at the bottom, scroll all the way down to let users see that
+    // they have reached the bottom of the zero state view.
+    ScrollRectToVisible(gfx::Rect(GetLocalBounds().bottom_left(), gfx::Size()));
+  } else {
+    // Otherwise, just ensure the item is visible.
+    pseudo_focused_item_->ScrollViewToVisible();
+  }
+}
+
 BEGIN_METADATA(PickerZeroStateView)
 END_METADATA
 
diff --git a/ash/picker/views/picker_zero_state_view.h b/ash/picker/views/picker_zero_state_view.h
index 735ece9..82e51a1 100644
--- a/ash/picker/views/picker_zero_state_view.h
+++ b/ash/picker/views/picker_zero_state_view.h
@@ -19,6 +19,8 @@
 
 namespace ash {
 
+class PickerItemView;
+class PickerSectionListView;
 class PickerSectionView;
 
 class ASH_EXPORT PickerZeroStateView : public PickerPageView {
@@ -36,7 +38,11 @@
   ~PickerZeroStateView() override;
 
   // PickerPageView:
-  bool OnEnterKeyPressed() override;
+  bool DoPseudoFocusedAction() override;
+  bool MovePseudoFocusUp() override;
+  bool MovePseudoFocusDown() override;
+  bool MovePseudoFocusLeft() override;
+  bool MovePseudoFocusRight() override;
 
   std::map<PickerCategoryType, raw_ptr<PickerSectionView>>
   section_views_for_testing() const {
@@ -47,11 +53,19 @@
   // Gets or creates the section to contain `category`.
   PickerSectionView* GetOrCreateSectionView(PickerCategory category);
 
-  // Width of the containing PickerView.
-  int picker_view_width_ = 0;
+  void SetPseudoFocusedItem(PickerItemView* item);
 
-  // The views for each section of categories.
+  void ScrollPseudoFocusedItemToVisible();
+
+  // The section list view, contains the section views.
+  raw_ptr<PickerSectionListView> section_list_view_ = nullptr;
+
+  // Used to track the section view for each category type.
   std::map<PickerCategoryType, raw_ptr<PickerSectionView>> section_views_;
+
+  // The currently pseudo focused item, which responds to user actions that
+  // trigger `DoPseudoFocusedAction`.
+  raw_ptr<PickerItemView> pseudo_focused_item_ = nullptr;
 };
 
 }  // namespace ash
diff --git a/ash/public/cpp/new_window_delegate.h b/ash/public/cpp/new_window_delegate.h
index 45d7ae3..5e98a17 100644
--- a/ash/public/cpp/new_window_delegate.h
+++ b/ash/public/cpp/new_window_delegate.h
@@ -130,6 +130,9 @@
   // Show the Personalization hub.
   virtual void OpenPersonalizationHub() = 0;
 
+  // Shows the a captive portal signin window.
+  virtual void OpenCaptivePortalSignin(const GURL& url) = 0;
+
  protected:
   NewWindowDelegate();
   NewWindowDelegate(const NewWindowDelegate&) = delete;
diff --git a/ash/public/cpp/picker/picker_client.h b/ash/public/cpp/picker/picker_client.h
index a3a4498..122a6a8 100644
--- a/ash/public/cpp/picker/picker_client.h
+++ b/ash/public/cpp/picker/picker_client.h
@@ -13,6 +13,7 @@
 #include "ash/public/cpp/app_list/app_list_types.h"
 #include "ash/public/cpp/ash_public_export.h"
 #include "ash/public/cpp/ash_web_view.h"
+#include "ash/public/cpp/picker/picker_category.h"
 #include "ash/public/cpp/picker/picker_search_result.h"
 #include "base/functional/callback_forward.h"
 #include "base/memory/scoped_refptr.h"
@@ -52,6 +53,7 @@
   // Starts a search using the CrOS Search API
   // (`app_list::SearchEngine::StartSearch`).
   virtual void StartCrosSearch(const std::u16string& query,
+                               std::optional<PickerCategory> category,
                                CrosSearchResultsCallback callback) = 0;
   // Stops a search using the CrOS Search API
   // (`app_list::SearchEngine::StopQuery`).
diff --git a/ash/public/cpp/picker/picker_search_result.cc b/ash/public/cpp/picker/picker_search_result.cc
index f0a40b6..22769b7 100644
--- a/ash/public/cpp/picker/picker_search_result.cc
+++ b/ash/public/cpp/picker/picker_search_result.cc
@@ -26,13 +26,17 @@
 bool PickerSearchResult::EmoticonData::operator==(
     const PickerSearchResult::EmoticonData&) const = default;
 
-PickerSearchResult::GifData::GifData(const GURL& url,
+PickerSearchResult::GifData::GifData(const GURL& preview_url,
                                      const GURL& preview_image_url,
-                                     const gfx::Size& dimensions,
+                                     const gfx::Size& preview_dimensions,
+                                     const GURL& full_url,
+                                     const gfx::Size& full_dimensions,
                                      std::u16string content_description)
-    : url(url),
+    : preview_url(preview_url),
       preview_image_url(preview_image_url),
-      dimensions(dimensions),
+      preview_dimensions(preview_dimensions),
+      full_url(full_url),
+      full_dimensions(full_dimensions),
       content_description(std::move(content_description)) {}
 
 PickerSearchResult::GifData::GifData(const PickerSearchResult::GifData&) =
@@ -75,12 +79,15 @@
   return PickerSearchResult(EmoticonData{.emoticon = std::u16string(emoticon)});
 }
 
-PickerSearchResult PickerSearchResult::Gif(const GURL& url,
+PickerSearchResult PickerSearchResult::Gif(const GURL& preview_url,
                                            const GURL& preview_image_url,
-                                           const gfx::Size& dimensions,
+                                           const gfx::Size& preview_dimensions,
+                                           const GURL& full_url,
+                                           const gfx::Size& full_dimensions,
                                            std::u16string content_description) {
-  return PickerSearchResult(GifData(url, preview_image_url, dimensions,
-                                    std::move(content_description)));
+  return PickerSearchResult(
+      GifData(preview_url, preview_image_url, preview_dimensions, full_url,
+              full_dimensions, std::move(content_description)));
 }
 
 PickerSearchResult PickerSearchResult::BrowsingHistory(const GURL& url,
diff --git a/ash/public/cpp/picker/picker_search_result.h b/ash/public/cpp/picker/picker_search_result.h
index cf3873f..3ff9293 100644
--- a/ash/public/cpp/picker/picker_search_result.h
+++ b/ash/public/cpp/picker/picker_search_result.h
@@ -46,22 +46,30 @@
   };
 
   struct GifData {
-    GifData(const GURL& url,
+    GifData(const GURL& preview_url,
             const GURL& preview_image_url,
-            const gfx::Size& dimensions,
+            const gfx::Size& preview_dimensions,
+            const GURL& full_url,
+            const gfx::Size& full_dimensions,
             std::u16string content_description);
     GifData(const GifData&);
     GifData& operator=(const GifData&);
     ~GifData();
 
-    // A url to the gif media source.
-    GURL url;
+    // A url to an animated preview gif media source.
+    GURL preview_url;
 
-    // A url to a preview image of the gif media source.
+    // A url to an unanimated preview image of the gif media source.
     GURL preview_image_url;
 
-    // Width and height of the GIF at `url`.
-    gfx::Size dimensions;
+    // Width and height of the GIF at `preview_url`.
+    gfx::Size preview_dimensions;
+
+    // A url to a full-sized gif media source.
+    GURL full_url;
+
+    // Width and height of the GIF at `full_url`.
+    gfx::Size full_dimensions;
 
     // A textual description of the content, primarily used for accessibility
     // features.
@@ -103,9 +111,11 @@
   static PickerSearchResult Emoji(std::u16string_view emoji);
   static PickerSearchResult Symbol(std::u16string_view symbol);
   static PickerSearchResult Emoticon(std::u16string_view emoticon);
-  static PickerSearchResult Gif(const GURL& url,
+  static PickerSearchResult Gif(const GURL& preview_url,
                                 const GURL& preview_image_url,
-                                const gfx::Size& dimensions,
+                                const gfx::Size& preview_dimensions,
+                                const GURL& full_url,
+                                const gfx::Size& full_dimensions,
                                 std::u16string content_description);
   static PickerSearchResult Category(PickerCategory category);
 
diff --git a/ash/public/cpp/test/test_new_window_delegate.cc b/ash/public/cpp/test/test_new_window_delegate.cc
index 736c63c..0ff2f7af 100644
--- a/ash/public/cpp/test/test_new_window_delegate.cc
+++ b/ash/public/cpp/test/test_new_window_delegate.cc
@@ -39,6 +39,7 @@
     FeedbackSource source,
     const std::string& description_template) {}
 void TestNewWindowDelegate::OpenPersonalizationHub() {}
+void TestNewWindowDelegate::OpenCaptivePortalSignin(const GURL& url) {}
 
 TestNewWindowDelegateProvider::TestNewWindowDelegateProvider(
     std::unique_ptr<TestNewWindowDelegate> delegate)
diff --git a/ash/public/cpp/test/test_new_window_delegate.h b/ash/public/cpp/test/test_new_window_delegate.h
index 7c33063..d5eb507 100644
--- a/ash/public/cpp/test/test_new_window_delegate.h
+++ b/ash/public/cpp/test/test_new_window_delegate.h
@@ -43,6 +43,7 @@
   void OpenFeedbackPage(FeedbackSource source,
                         const std::string& description_template) override;
   void OpenPersonalizationHub() override;
+  void OpenCaptivePortalSignin(const GURL& url) override;
 };
 
 // NewWindowDelegateProvider implementation to provide TestNewWindowDelegate.
diff --git a/ash/root_window_controller.h b/ash/root_window_controller.h
index bddc854..491a9e6 100644
--- a/ash/root_window_controller.h
+++ b/ash/root_window_controller.h
@@ -13,7 +13,6 @@
 #include "ash/style/ash_color_provider_source.h"
 #include "ash/wm/overview/overview_metrics.h"
 #include "ash/wm/overview/overview_types.h"
-#include "ash/wm/splitview/split_view_overview_session.h"
 #include "ash/wm/wm_metrics.h"
 #include "base/memory/raw_ptr.h"
 #include "ui/aura/window_tree_host.h"
@@ -61,6 +60,7 @@
 class WindowParentingController;
 class WorkAreaInsets;
 enum class LoginStatus;
+enum class SplitViewOverviewSessionExitPoint;
 
 namespace curtain {
 class SecurityCurtainWidgetController;
diff --git a/ash/search_box/search_box_view_base.cc b/ash/search_box/search_box_view_base.cc
index 58e8a2c..de088fe 100644
--- a/ash/search_box/search_box_view_base.cc
+++ b/ash/search_box/search_box_view_base.cc
@@ -89,7 +89,7 @@
                     gfx::Insets border_insets,
                     ui::ColorId color_id) {
   label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  label->GetViewAccessibility().OverrideIsIgnored(true);
+  label->GetViewAccessibility().SetIsIgnored(true);
   label->SetBackgroundColor(SK_ColorTRANSPARENT);
   label->SetAutoColorReadabilityEnabled(false);
   label->SetEnabledColorId(color_id);
@@ -243,8 +243,8 @@
     // alert, so we ignored the search box in those cases. Now reset the flag
     // here.
     auto& accessibility = GetViewAccessibility();
-    if (accessibility.IsIgnored()) {
-      accessibility.OverrideIsIgnored(false);
+    if (accessibility.GetIsIgnored()) {
+      accessibility.SetIsIgnored(false);
       NotifyAccessibilityEvent(ax::mojom::Event::kTreeChanged, true);
     }
   }
diff --git a/ash/shelf/drag_handle.h b/ash/shelf/drag_handle.h
index fc051f56..90814c5 100644
--- a/ash/shelf/drag_handle.h
+++ b/ash/shelf/drag_handle.h
@@ -19,6 +19,7 @@
 #include "base/scoped_observation.h"
 #include "base/timer/timer.h"
 #include "ui/base/metadata/metadata_header_macros.h"
+#include "ui/compositor/layer_animation_observer.h"
 #include "ui/compositor/layer_animator.h"
 #include "ui/views/controls/button/button.h"
 #include "ui/views/view_targeter_delegate.h"
diff --git a/ash/shelf/drag_window_from_shelf_controller.cc b/ash/shelf/drag_window_from_shelf_controller.cc
index f0611fe..44654a5 100644
--- a/ash/shelf/drag_window_from_shelf_controller.cc
+++ b/ash/shelf/drag_window_from_shelf_controller.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include "ash/shelf/drag_window_from_shelf_controller.h"
-#include "base/memory/raw_ptr.h"
 
 #include <algorithm>
 
@@ -39,12 +38,14 @@
 #include "ash/wm/window_util.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
+#include "base/memory/raw_ptr.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/ranges/algorithm.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/base/hit_test.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/layer_animation_observer.h"
+#include "ui/compositor/layer_tree_owner.h"
 #include "ui/compositor/presentation_time_recorder.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/display/screen.h"
diff --git a/ash/shelf/drag_window_from_shelf_controller.h b/ash/shelf/drag_window_from_shelf_controller.h
index 177d29b7..81d57a1 100644
--- a/ash/shelf/drag_window_from_shelf_controller.h
+++ b/ash/shelf/drag_window_from_shelf_controller.h
@@ -19,6 +19,7 @@
 #include "base/observer_list.h"
 #include "base/timer/timer.h"
 #include "ui/aura/window_observer.h"
+#include "ui/compositor/layer_tree_owner.h"
 
 namespace aura {
 class Window;
diff --git a/ash/shelf/scrollable_shelf_view.cc b/ash/shelf/scrollable_shelf_view.cc
index 6d16cd2..a91c9dd0 100644
--- a/ash/shelf/scrollable_shelf_view.cc
+++ b/ash/shelf/scrollable_shelf_view.cc
@@ -112,7 +112,7 @@
     // the hidden icon which receives the accessibility focus shows through
     // scroll animation. So the arrow button is not useful for the spoken
     // feedback users. The spoken feedback should ignore the arrow button.
-    GetViewAccessibility().OverrideIsIgnored(/*value=*/true);
+    GetViewAccessibility().SetIsIgnored(/*value=*/true);
   }
   ~ScrollableShelfArrowView() override = default;
 
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h
index d3694f96..69ed59b 100644
--- a/ash/shelf/shelf_layout_manager.h
+++ b/ash/shelf/shelf_layout_manager.h
@@ -30,6 +30,7 @@
 #include "ash/wm/splitview/split_view_observer.h"
 #include "ash/wm/wm_default_layout_manager.h"
 #include "ash/wm/workspace/workspace_types.h"
+#include "base/cancelable_callback.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
diff --git a/ash/shelf/test/hotseat_state_watcher.cc b/ash/shelf/test/hotseat_state_watcher.cc
index d3ec4107..44d7f35 100644
--- a/ash/shelf/test/hotseat_state_watcher.cc
+++ b/ash/shelf/test/hotseat_state_watcher.cc
@@ -4,6 +4,8 @@
 
 #include "ash/shelf/test/hotseat_state_watcher.h"
 
+#include "ash/shelf/shelf_layout_manager_observer.h"
+
 namespace ash {
 
 HotseatStateWatcher::HotseatStateWatcher(
diff --git a/ash/shelf/test/hotseat_state_watcher.h b/ash/shelf/test/hotseat_state_watcher.h
index 15e9f52e..5ccd6c29 100644
--- a/ash/shelf/test/hotseat_state_watcher.h
+++ b/ash/shelf/test/hotseat_state_watcher.h
@@ -7,6 +7,7 @@
 
 #include "ash/shelf/shelf_layout_manager.h"
 #include "base/memory/raw_ptr.h"
+#include "base/run_loop.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace ash {
diff --git a/ash/strings/ash_strings_af.xtb b/ash/strings/ash_strings_af.xtb
index 3c76338..ef62113 100644
--- a/ash/strings/ash_strings_af.xtb
+++ b/ash/strings/ash_strings_af.xtb
@@ -1896,7 +1896,6 @@
 <translation id="8553395910833293175">Reeds toegewys aan alle lessenaars.</translation>
 <translation id="8555757996376137129">Verwyder huidige lessenaar</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> beveel aan dat jy jou <ph name="DEVICE_TYPE" /> opdateer</translation>
-<translation id="8563862697512465947">Kennisgewinginstellings</translation>
 <translation id="8569751806372591456">Hier is ’n paar voorstelle om te probeer</translation>
 <translation id="857201607579416096">Kieslys is na die skerm se hoek regs onder geskuif.</translation>
 <translation id="8581946341807941670">Druk <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> en klik ’n skakel</translation>
diff --git a/ash/strings/ash_strings_am.xtb b/ash/strings/ash_strings_am.xtb
index 4e54924..0c2378dd 100644
--- a/ash/strings/ash_strings_am.xtb
+++ b/ash/strings/ash_strings_am.xtb
@@ -1896,7 +1896,6 @@
 <translation id="8553395910833293175">ለሁሉም ዴስኮች ቀድሞውኑ ተመድቧል።</translation>
 <translation id="8555757996376137129">የአሁኑን ዴስክ አስወግድ</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> የእርስዎን <ph name="DEVICE_TYPE" /> እንዲያዘምኑ ይመክራል</translation>
-<translation id="8563862697512465947">የማስታወቂያ ቅንብሮች </translation>
 <translation id="8569751806372591456">የመሞከሪያ ጥቂት ጥቆማዎች እነሆ</translation>
 <translation id="857201607579416096">ምናሌ ወደ የማያ ገጹ የታችኛው ቀኝ ጥግ ተወስዷል።</translation>
 <translation id="8581946341807941670"><ph name="MODIFIER_1" /><ph name="MODIFIER_2" />ን ይጫኑ እና አገናኝ ላይ ጠቅ ያድርጉ</translation>
diff --git a/ash/strings/ash_strings_ar.xtb b/ash/strings/ash_strings_ar.xtb
index 666da0b..bce7f3b0 100644
--- a/ash/strings/ash_strings_ar.xtb
+++ b/ash/strings/ash_strings_ar.xtb
@@ -1898,7 +1898,6 @@
 <translation id="8553395910833293175">سبقَ نقل المحتوى المرئي إلى جميع أسطح المكتب.</translation>
 <translation id="8555757996376137129">إزالة سطح المكتب الحالي</translation>
 <translation id="856298576161209842">يقترح <ph name="MANAGER" /> عليك تحديث جهاز <ph name="DEVICE_TYPE" />.</translation>
-<translation id="8563862697512465947">إعدادات الاشعارات</translation>
 <translation id="8569751806372591456">إليك بعض الاقتراحات للتجربة:</translation>
 <translation id="857201607579416096">تم نقل القائمة إلى أسفل يسار الشاشة.</translation>
 <translation id="8581946341807941670">‏اضغط على ‎<ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> ثم انقر على الرابط.</translation>
diff --git a/ash/strings/ash_strings_as.xtb b/ash/strings/ash_strings_as.xtb
index 34f058e..7c3300c 100644
--- a/ash/strings/ash_strings_as.xtb
+++ b/ash/strings/ash_strings_as.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">ইতিমধ্যে আটাইবোৰ ডেস্কক দায়িত্ব প্ৰদান কৰা হৈছে।</translation>
 <translation id="8555757996376137129">বৰ্তমানৰ ডেস্ক আঁতৰাওক</translation>
 <translation id="856298576161209842"><ph name="MANAGER" />এ আপোনাক নিজৰ <ph name="DEVICE_TYPE" />টো আপডে’ট কৰিবলৈ চুপাৰিছ কৰে</translation>
-<translation id="8563862697512465947">জাননীৰ ছেটিংসমূহ</translation>
 <translation id="8569751806372591456">এয়া আপুনি কৰিব চাব পৰা কিছুমান পৰামৰ্শ</translation>
 <translation id="857201607579416096">স্ক্ৰীনখনৰ তলৰ সোঁফালৰ কোণটোলৈ মেনুখন নিয়া হৈছে।</translation>
 <translation id="8581946341807941670"><ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> টিপক আৰু এটা লিংকত ক্লিক কৰক</translation>
diff --git a/ash/strings/ash_strings_az.xtb b/ash/strings/ash_strings_az.xtb
index 3716669a..1bcf56c4 100644
--- a/ash/strings/ash_strings_az.xtb
+++ b/ash/strings/ash_strings_az.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Artıq bütün masalara təyin olunub.</translation>
 <translation id="8555757996376137129">Cari masanı silin</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> <ph name="DEVICE_TYPE" /> cihazını güncəlləməyinizi tövsiyə edir</translation>
-<translation id="8563862697512465947">Bildiriş Ayarları</translation>
 <translation id="8569751806372591456">Sınamaq üçün bəzi təkliflər</translation>
 <translation id="857201607579416096">Menyu ekranın aşağı sağ küncünə köçürülüb.</translation>
 <translation id="8581946341807941670"><ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> üzərinə basıb, keçidə klikləyin</translation>
diff --git a/ash/strings/ash_strings_be.xtb b/ash/strings/ash_strings_be.xtb
index fe1bbc75..56ed9c9 100644
--- a/ash/strings/ash_strings_be.xtb
+++ b/ash/strings/ash_strings_be.xtb
@@ -358,6 +358,7 @@
 <translation id="2484513351006226581">Каб пераключыць раскладку клавіятуры, націсніце <ph name="KEYBOARD_SHORTCUT" />.</translation>
 <translation id="2486214324139475545">Перадпрагляд працоўнага стала "<ph name="DESK_NAME" />". Актыўны працоўны стол.</translation>
 <translation id="2487915095798731898">Далучыцца</translation>
+<translation id="2499445554382787206">Меню профілю працоўнага стала. <ph name="DESK_NAME" /></translation>
 <translation id="2501920221385095727">Заліпанне клавіш</translation>
 <translation id="2504454902900101003">Не наладжваць прагляд нядаўніх фота, медыяфайлаў і апавяшчэнняў з тэлефона</translation>
 <translation id="2509468283778169019">CAPS LOCK уключаны</translation>
@@ -604,6 +605,7 @@
 <translation id="3509391053705095206">Не ўдалося знайсці тэлефон. Пераканайцеся, што на тэлефоне ўключаны Bluetooth.</translation>
 <translation id="3510164367642747937">Вылучаць курсор мышы</translation>
 <translation id="3513798432020909783">Уліковы запіс пад кіраваннем <ph name="MANAGER_EMAIL" /></translation>
+<translation id="3517037892157925473">Апошняе абнаўленне задач: <ph name="TIME" />, <ph name="DATE" />.</translation>
 <translation id="352245152354538528">{0,plural, =1{Абнавіце прыладу на працягу 1 хвіліны}one{Абнавіце прыладу на працягу # хвіліны}few{Абнавіце прыладу на працягу # хвілін}many{Абнавіце прыладу на працягу # хвілін}other{Абнавіце прыладу на працягу # хвілін}}</translation>
 <translation id="3522979239100719575">Ідзе пошук даступных профіляў. Гэта можа заняць некалькі хвілін.</translation>
 <translation id="3526440770046466733">Адкрыць спасылку ў новай укладцы, але заставацца на бягучай</translation>
@@ -1142,6 +1144,7 @@
 <translation id="5536723544185013515">Нядаўнія праграмы: для пераходу паміж імі выкарыстоўвайце клавішы са стрэлкамі ўлева і ўправа</translation>
 <translation id="553675580533261935">Выконваецца выхад з сеанса</translation>
 <translation id="5537725057119320332">Трансліраваць</translation>
+<translation id="554017492391497564">Не ўдалося пазначыць задачу як выкананую.</translation>
 <translation id="5546397813406633847">Аднавіць доступ для карыстальніка</translation>
 <translation id="554893713779400387">Уключыць або выключыць галасавы ўвод</translation>
 <translation id="5550417424894892620">Перацягніце файлы на працоўны стол, каб дадаць іх у вобласць "<ph name="HOLDING_SPACE_TITLE" />". Вы не можаце дадаць файлы на працоўны стол.</translation>
@@ -1336,6 +1339,7 @@
 <translation id="6237231532760393653">1X</translation>
 <translation id="62380141479352646">Нізкі зарад акумулятара. Уключаны рэжым энергазберажэння.</translation>
 <translation id="6247728804802644171">Адкрыць апавяшчэнні</translation>
+<translation id="6249795363855770621">Не ўдалося пазначыць задачу як выкананую. Паўтарыце спробу, калі падключэнне да інтэрнэту будзе адноўлена.</translation>
 <translation id="6254629735336163724">Зафіксаваны гарызантальны фармат</translation>
 <translation id="6259254695169772643">Для выбару выкарыстайце стыло</translation>
 <translation id="6267036997247669271"><ph name="NAME" />: ідзе актывацыя...</translation>
@@ -1496,6 +1500,7 @@
 <translation id="6896758677409633944">Капіраваць</translation>
 <translation id="6912841030378044227">Перайсці ў адрасны радок</translation>
 <translation id="6912901278692845878">Кароткі агляд</translation>
+<translation id="6917259695595127329">Апошняе абнаўленне задач: <ph name="TIME" />.</translation>
 <translation id="6919251195245069855">Не ўдалося распазнаць вашу разумную картку. Паўтарыце спробу.</translation>
 <translation id="692135145298539227">выдаліць</translation>
 <translation id="6929081673585394903">Паказаць элементы кіравання</translation>
@@ -1895,7 +1900,6 @@
 <translation id="8553395910833293175">Акно ўжо даступнае на ўсіх працоўных сталах.</translation>
 <translation id="8555757996376137129">Выдаліць бягучы працоўны стол</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> рэкамендуе вам абнавіць прыладу <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Налады апавяшчэнняў</translation>
 <translation id="8569751806372591456">Вось некалькі прапаноў</translation>
 <translation id="857201607579416096">Меню перамешчана ў правы ніжні вугал экрана.</translation>
 <translation id="8581946341807941670">Трымайце <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> і націсніце на спасылку</translation>
diff --git a/ash/strings/ash_strings_bg.xtb b/ash/strings/ash_strings_bg.xtb
index 9faf26f4..2ac3d05 100644
--- a/ash/strings/ash_strings_bg.xtb
+++ b/ash/strings/ash_strings_bg.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Вече е прехвърлено във всички работни кътове.</translation>
 <translation id="8555757996376137129">Премахване на текущия работен кът</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> препоръчва да актуализирате устройството си <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Настройки за известия</translation>
 <translation id="8569751806372591456">Ето няколко предложения, които да изпробвате</translation>
 <translation id="857201607579416096">Менюто е преместено в долния десен ъгъл на екрана.</translation>
 <translation id="8581946341807941670">Натиснете <ph name="MODIFIER_1" /> + <ph name="MODIFIER_2" /> и кликнете върху връзка</translation>
diff --git a/ash/strings/ash_strings_bn.xtb b/ash/strings/ash_strings_bn.xtb
index 38c53a9..c1134bc5 100644
--- a/ash/strings/ash_strings_bn.xtb
+++ b/ash/strings/ash_strings_bn.xtb
@@ -1896,7 +1896,6 @@
 <translation id="8553395910833293175">সব ডেস্কে আগেই অ্যাসাইন করা হয়েছে।</translation>
 <translation id="8555757996376137129">বর্তমান ডেস্ক সরিয়ে দিন</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> আপনার <ph name="DEVICE_TYPE" /> আপডেট করার সাজেশন দিচ্ছে</translation>
-<translation id="8563862697512465947">বিজ্ঞপ্তি সেটিংস</translation>
 <translation id="8569751806372591456">চেষ্টা করে দেখতে পারেন এমন কয়েকটি সাজেশন দেওয়া হল</translation>
 <translation id="857201607579416096">স্ক্রিনের নিচে ডানদিকের কোণায় মেনু সরে গেছে।</translation>
 <translation id="8581946341807941670"><ph name="MODIFIER_1" /> <ph name="MODIFIER_2" /> প্রেস করুন এবং একটি লিঙ্কে ক্লিক করুন</translation>
diff --git a/ash/strings/ash_strings_bs.xtb b/ash/strings/ash_strings_bs.xtb
index 09088d8..c10da56 100644
--- a/ash/strings/ash_strings_bs.xtb
+++ b/ash/strings/ash_strings_bs.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Već je dodijeljeno svim radnim površinama.</translation>
 <translation id="8555757996376137129">Ukloni trenutnu radnu površinu</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> preporučuje da ažurirate uređaj <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Postavke obavještenja</translation>
 <translation id="8569751806372591456">Evo nekoliko prijedloga koje možete isprobati</translation>
 <translation id="857201607579416096">Meni je pomjeren u donji desni ugao ekrana.</translation>
 <translation id="8581946341807941670">Pritisnite <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> i kliknite na link</translation>
diff --git a/ash/strings/ash_strings_ca.xtb b/ash/strings/ash_strings_ca.xtb
index 2117be8..bb7e645 100644
--- a/ash/strings/ash_strings_ca.xtb
+++ b/ash/strings/ash_strings_ca.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Ja està assignada a tots els escriptoris.</translation>
 <translation id="8555757996376137129">Suprimeix l'escriptori actual</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> et recomana que actualitzis el dispositiu <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Configuració de notificació</translation>
 <translation id="8569751806372591456">Aquí tens alguns suggeriments que pots provar</translation>
 <translation id="857201607579416096">El menú s'ha mogut a l'extrem inferior dret de la pantalla.</translation>
 <translation id="8581946341807941670">Prem <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> i fes clic en un enllaç</translation>
diff --git a/ash/strings/ash_strings_cs.xtb b/ash/strings/ash_strings_cs.xtb
index 9a9e6f5..0f76ac3 100644
--- a/ash/strings/ash_strings_cs.xtb
+++ b/ash/strings/ash_strings_cs.xtb
@@ -358,6 +358,7 @@
 <translation id="2484513351006226581">Rozložení klávesnice změníte stisknutím kláves <ph name="KEYBOARD_SHORTCUT" /></translation>
 <translation id="2486214324139475545">Náhled plochy <ph name="DESK_NAME" />. Aktivní plocha.</translation>
 <translation id="2487915095798731898">Připojit se</translation>
+<translation id="2499445554382787206">Nabídka profilu plochy. <ph name="DESK_NAME" /></translation>
 <translation id="2501920221385095727">Jedním prstem</translation>
 <translation id="2504454902900101003">Zavřít nastavení zobrazování nedávných fotek, médií a oznámení z telefonu</translation>
 <translation id="2509468283778169019">CAPS LOCK je zapnutý</translation>
@@ -604,6 +605,7 @@
 <translation id="3509391053705095206">Telefon se nepodařilo najít. Zkontrolujte, jestli je na něm zapnutý Bluetooth.</translation>
 <translation id="3510164367642747937">Zvýraznit ukazatel myši</translation>
 <translation id="3513798432020909783">Správce účtu: <ph name="MANAGER_EMAIL" /></translation>
+<translation id="3517037892157925473">Poslední aktualizace úkolů: <ph name="TIME" />, <ph name="DATE" />.</translation>
 <translation id="352245152354538528">{0,plural, =1{Do jedné minuty zařízení aktualizujte}few{Do # minut zařízení aktualizujte}many{Do # minuty zařízení aktualizujte}other{Do # minut zařízení aktualizujte}}</translation>
 <translation id="3522979239100719575">Probíhá vyhledávání dostupných profilů. Může to trvat několik minut.</translation>
 <translation id="3526440770046466733">Otevřít odkaz na nové kartě a zůstat na aktuální kartě</translation>
@@ -1142,6 +1144,7 @@
 <translation id="5536723544185013515">Nedávné aplikace, můžete je procházet pomocí kláves se šipkami vlevo a vpravo</translation>
 <translation id="553675580533261935">Ukončení návštěvy</translation>
 <translation id="5537725057119320332">Odeslat</translation>
+<translation id="554017492391497564">Nelze označit jako dokončené.</translation>
 <translation id="5546397813406633847">Obnovit uživatele</translation>
 <translation id="554893713779400387">Přepnout diktování</translation>
 <translation id="5550417424894892620">Soubory přetažené na plochu budou přidány do prostoru <ph name="HOLDING_SPACE_TITLE" />. Na plochu soubory přidat nemůžete.</translation>
@@ -1336,6 +1339,7 @@
 <translation id="6237231532760393653">1X</translation>
 <translation id="62380141479352646">Baterie je téměř vybitá. Zapnul se spořič baterie.</translation>
 <translation id="6247728804802644171">Otevřít oznámení</translation>
+<translation id="6249795363855770621">Nelze označit jako dokončené. Zkuste to, až budete online.</translation>
 <translation id="6254629735336163724">Uzamknuto na šířku</translation>
 <translation id="6259254695169772643">K výběru použijte dotykové pero</translation>
 <translation id="6267036997247669271"><ph name="NAME" />: Probíhá aktivace...</translation>
@@ -1496,6 +1500,7 @@
 <translation id="6896758677409633944">Kopírovat</translation>
 <translation id="6912841030378044227">Přejít do adresního řádku</translation>
 <translation id="6912901278692845878">Rychlá prohlídka</translation>
+<translation id="6917259695595127329">Poslední aktualizace úkolů: <ph name="TIME" />.</translation>
 <translation id="6919251195245069855">Chytrou kartu se nepodařilo rozpoznat. Zkuste to znovu.</translation>
 <translation id="692135145298539227">smazat</translation>
 <translation id="6929081673585394903">Zobrazit ovládací prvky</translation>
@@ -1894,7 +1899,6 @@
 <translation id="8553395910833293175">Již přiřazeno ke všem plochám.</translation>
 <translation id="8555757996376137129">Odstranit aktuální plochu</translation>
 <translation id="856298576161209842">Organizace <ph name="MANAGER" /> vám doporučuje, abyste toto zařízení <ph name="DEVICE_TYPE" /> aktualizovali</translation>
-<translation id="8563862697512465947">Nastavení oznámení</translation>
 <translation id="8569751806372591456">Zde je několik návrhů, které můžete vyzkoušet</translation>
 <translation id="857201607579416096">Nabídka byla přesunuta do pravého dolního rohu obrazovky.</translation>
 <translation id="8581946341807941670">Stiskněte <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> a klikněte na odkaz</translation>
diff --git a/ash/strings/ash_strings_cy.xtb b/ash/strings/ash_strings_cy.xtb
index 16dc718..4b118a05 100644
--- a/ash/strings/ash_strings_cy.xtb
+++ b/ash/strings/ash_strings_cy.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Wedi'i haseinio i bob desg yn barod.</translation>
 <translation id="8555757996376137129">Tynnu'r ddesg bresennol</translation>
 <translation id="856298576161209842">Mae <ph name="MANAGER" /> yn argymell eich bod yn diweddaru eich <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Gosodiadau Hysbysiadau</translation>
 <translation id="8569751806372591456">Dyma ychydig o awgrymiadau i roi cynnig arnynt</translation>
 <translation id="857201607579416096">Cafodd y ddewislen ei symud i gornel dde waelod y sgrîn.</translation>
 <translation id="8581946341807941670">Pwyswch <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> a chliciwch ddolen</translation>
diff --git a/ash/strings/ash_strings_da.xtb b/ash/strings/ash_strings_da.xtb
index e12f4aa6..7d2e4f3 100644
--- a/ash/strings/ash_strings_da.xtb
+++ b/ash/strings/ash_strings_da.xtb
@@ -1888,7 +1888,6 @@
 <translation id="8553395910833293175">Allerede tildelt til alle skriveborde.</translation>
 <translation id="8555757996376137129">Fjern det aktuelle skrivebord</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> anbefaler, at du opdaterer din <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Indstillinger for notifikationer</translation>
 <translation id="8569751806372591456">Her er nogle forslag til, hvad du kan prøve</translation>
 <translation id="857201607579416096">Menuen blev flyttet til nederste højre hjørne af skærmen.</translation>
 <translation id="8581946341807941670">Tryk på <ph name="MODIFIER_1" /><ph name="MODIFIER_2" />, og klik på et link</translation>
diff --git a/ash/strings/ash_strings_de.xtb b/ash/strings/ash_strings_de.xtb
index 2087ba0..7fa5b9c 100644
--- a/ash/strings/ash_strings_de.xtb
+++ b/ash/strings/ash_strings_de.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Ist bereits allen Desktops zugewiesen.</translation>
 <translation id="8555757996376137129">Aktuellen Desktop entfernen</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> empfiehlt, dein Gerät (<ph name="DEVICE_TYPE" />) zu aktualisieren</translation>
-<translation id="8563862697512465947">Benachrichtigungseinstellungen</translation>
 <translation id="8569751806372591456">Hier ein paar Vorschläge</translation>
 <translation id="857201607579416096">Menü wurde nach rechts unten auf dem Bildschirm verschoben.</translation>
 <translation id="8581946341807941670"><ph name="MODIFIER_1" /> + <ph name="MODIFIER_2" /> drücken und auf einen Link klicken</translation>
diff --git a/ash/strings/ash_strings_el.xtb b/ash/strings/ash_strings_el.xtb
index 0a71048..2a1ce75c 100644
--- a/ash/strings/ash_strings_el.xtb
+++ b/ash/strings/ash_strings_el.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Έχει εκχωρηθεί ήδη σε όλα τα γραφεία.</translation>
 <translation id="8555757996376137129">Κατάργηση τρέχοντος γραφείου</translation>
 <translation id="856298576161209842">Ο τομέας <ph name="MANAGER" /> προτείνει να ενημερώσετε τη συσκευή <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Ρυθμίσεις ειδοποίησης</translation>
 <translation id="8569751806372591456">Δείτε μερικές προτάσεις που μπορείτε να δοκιμάσετε</translation>
 <translation id="857201607579416096">Το μενού μεταφέρθηκε στην κάτω δεξιά γωνία της οθόνης.</translation>
 <translation id="8581946341807941670">Πατήστε <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> και κάντε κλικ σε έναν σύνδεσμο</translation>
diff --git a/ash/strings/ash_strings_en-GB.xtb b/ash/strings/ash_strings_en-GB.xtb
index ccb7db18..f320cdd 100644
--- a/ash/strings/ash_strings_en-GB.xtb
+++ b/ash/strings/ash_strings_en-GB.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Already assigned to all desks.</translation>
 <translation id="8555757996376137129">Remove current desk</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> recommends that you update your <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Notification Settings</translation>
 <translation id="8569751806372591456">Here are a few suggestions to try</translation>
 <translation id="857201607579416096">Menu moved to the bottom-right corner of the screen.</translation>
 <translation id="8581946341807941670">Press <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> and click a link</translation>
diff --git a/ash/strings/ash_strings_es-419.xtb b/ash/strings/ash_strings_es-419.xtb
index bd5a2b1..f8d0bc6 100644
--- a/ash/strings/ash_strings_es-419.xtb
+++ b/ash/strings/ash_strings_es-419.xtb
@@ -1896,7 +1896,6 @@
 <translation id="8553395910833293175">Ya se asignó a todos los escritorios.</translation>
 <translation id="8555757996376137129">Quitar el escritorio actual</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> te recomienda que actualices tu <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Configuración de notificación</translation>
 <translation id="8569751806372591456">Estas son algunas sugerencias que puedes probar</translation>
 <translation id="857201607579416096">El menú se movió a la esquina inferior derecha de la pantalla.</translation>
 <translation id="8581946341807941670">Presiona <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> y haz clic en un vínculo</translation>
diff --git a/ash/strings/ash_strings_es.xtb b/ash/strings/ash_strings_es.xtb
index c9af840..3490f86 100644
--- a/ash/strings/ash_strings_es.xtb
+++ b/ash/strings/ash_strings_es.xtb
@@ -1896,7 +1896,6 @@
 <translation id="8553395910833293175">Ya está asignado a todos los escritorios.</translation>
 <translation id="8555757996376137129">Quitar escritorio actual</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> te recomienda que actualices tu <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Ajustes de notificaciones</translation>
 <translation id="8569751806372591456">Aquí tienes algunas sugerencias que puedes probar</translation>
 <translation id="857201607579416096">Se ha movido el menú a la esquina inferior derecha de la pantalla.</translation>
 <translation id="8581946341807941670">Pulsa <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> y haz clic en un enlace</translation>
diff --git a/ash/strings/ash_strings_et.xtb b/ash/strings/ash_strings_et.xtb
index 131499f..70c99e3 100644
--- a/ash/strings/ash_strings_et.xtb
+++ b/ash/strings/ash_strings_et.xtb
@@ -1896,7 +1896,6 @@
 <translation id="8553395910833293175">Juba määratud kõigile töölaudadele.</translation>
 <translation id="8555757996376137129">Eemaldage aktiivne töölaud</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> soovitab seadet <ph name="DEVICE_TYPE" /> värskendada</translation>
-<translation id="8563862697512465947">Teatiste seaded</translation>
 <translation id="8569751806372591456">Siin on proovimiseks mõned soovitused</translation>
 <translation id="857201607579416096">Menüü teisaldati ekraanikuva paremasse alanurka.</translation>
 <translation id="8581946341807941670">Vajutage klahvi <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> ja klõpsake lingil</translation>
diff --git a/ash/strings/ash_strings_eu.xtb b/ash/strings/ash_strings_eu.xtb
index e7b6543..4063dea 100644
--- a/ash/strings/ash_strings_eu.xtb
+++ b/ash/strings/ash_strings_eu.xtb
@@ -1896,7 +1896,6 @@
 <translation id="8553395910833293175">Lan-eremu guztiei esleitu zaie dagoeneko.</translation>
 <translation id="8555757996376137129">Kendu lan-eremu hau</translation>
 <translation id="856298576161209842"><ph name="DEVICE_TYPE" /> gailua eguneratzeko gomendatzen dizu <ph name="MANAGER" /> kudeatzaileak</translation>
-<translation id="8563862697512465947">Jakinarazpen-ezarpenak</translation>
 <translation id="8569751806372591456">Hona hemen proba ditzakezun gauza batzuk:</translation>
 <translation id="857201607579416096">Pantailaren beheko eskuineko izkinara eraman da menua.</translation>
 <translation id="8581946341807941670">Sakatu <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> eta egin klik esteka batean</translation>
diff --git a/ash/strings/ash_strings_fa.xtb b/ash/strings/ash_strings_fa.xtb
index f24ac7a..ed6f608 100644
--- a/ash/strings/ash_strings_fa.xtb
+++ b/ash/strings/ash_strings_fa.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">قبلاً به همه میزکارها اختصاص داده شده است.</translation>
 <translation id="8555757996376137129">حذف میزکار کنونی</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> توصیه می‌کند <ph name="DEVICE_TYPE" /> را به‌روزرسانی کنید</translation>
-<translation id="8563862697512465947">تنظیمات اعلام</translation>
 <translation id="8569751806372591456">چند پیشنهاد برای امتحان کردن:</translation>
 <translation id="857201607579416096">منو به گوشه چپ پایین صفحه منتقل شد.</translation>
 <translation id="8581946341807941670"><ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> را فشار دهید و روی پیوندی کلیک کنید</translation>
diff --git a/ash/strings/ash_strings_fi.xtb b/ash/strings/ash_strings_fi.xtb
index 7188a19..56ab058 100644
--- a/ash/strings/ash_strings_fi.xtb
+++ b/ash/strings/ash_strings_fi.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Lisätty jo kaikille työpöydille.</translation>
 <translation id="8555757996376137129">Poista nykyinen työpöytä</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> suosittelee, että <ph name="DEVICE_TYPE" /> päivitetään</translation>
-<translation id="8563862697512465947">Ilmoitusasetukset</translation>
 <translation id="8569751806372591456">Tässä on muutamia ehdotuksia</translation>
 <translation id="857201607579416096">Valikko siirretty näytön oikeaan alanurkkaan</translation>
 <translation id="8581946341807941670">Paina <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> ja klikkaa linkkiä</translation>
diff --git a/ash/strings/ash_strings_fil.xtb b/ash/strings/ash_strings_fil.xtb
index 96e7b68..cef7d94 100644
--- a/ash/strings/ash_strings_fil.xtb
+++ b/ash/strings/ash_strings_fil.xtb
@@ -1894,7 +1894,6 @@
 <translation id="8553395910833293175">Naitalaga na sa lahat ng desk.</translation>
 <translation id="8555757996376137129">Alisin ang kasalukuyang desk</translation>
 <translation id="856298576161209842">Inirerekomenda ng <ph name="MANAGER" /> na i-update mo ang iyong <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Mga Setting sa Abiso</translation>
 <translation id="8569751806372591456">Narito ang ilang suhestyong puwede mong subukan</translation>
 <translation id="857201607579416096">Inilipat ang menu sa kanang sulok sa ibaba ng screen.</translation>
 <translation id="8581946341807941670">Pindutin ang <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> at mag-click ng link</translation>
diff --git a/ash/strings/ash_strings_fr-CA.xtb b/ash/strings/ash_strings_fr-CA.xtb
index 65c1617..297949df 100644
--- a/ash/strings/ash_strings_fr-CA.xtb
+++ b/ash/strings/ash_strings_fr-CA.xtb
@@ -1894,7 +1894,6 @@
 <translation id="8553395910833293175">Association déjà faite sur tous les bureaux.</translation>
 <translation id="8555757996376137129">Retirer le bureau actuel</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> vous recommande de mettre à jour votre <ph name="DEVICE_TYPE" />.</translation>
-<translation id="8563862697512465947">Paramètres de notification</translation>
 <translation id="8569751806372591456">Voici quelques suggestions à essayer</translation>
 <translation id="857201607579416096">Le menu a été déplacé vers le coin inférieur droit de l'écran.</translation>
 <translation id="8581946341807941670">Appuyez sur <ph name="MODIFIER_1" /><ph name="MODIFIER_2" />, puis cliquez sur un lien</translation>
diff --git a/ash/strings/ash_strings_fr.xtb b/ash/strings/ash_strings_fr.xtb
index b350e6a..6c4772d5 100644
--- a/ash/strings/ash_strings_fr.xtb
+++ b/ash/strings/ash_strings_fr.xtb
@@ -1896,7 +1896,6 @@
 <translation id="8553395910833293175">Association déjà faite sur tous les bureaux.</translation>
 <translation id="8555757996376137129">Supprimer le bureau actuel</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> vous recommande de mettre à jour votre <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Paramètres de notification</translation>
 <translation id="8569751806372591456">Voici quelques suggestions à tester</translation>
 <translation id="857201607579416096">Le menu a été déplacé dans l'angle inférieur droit de l'écran.</translation>
 <translation id="8581946341807941670">Appuyez sur <ph name="MODIFIER_1" /><ph name="MODIFIER_2" />, puis cliquez sur un lien</translation>
diff --git a/ash/strings/ash_strings_gl.xtb b/ash/strings/ash_strings_gl.xtb
index 59c93cba..9ef7dc4 100644
--- a/ash/strings/ash_strings_gl.xtb
+++ b/ash/strings/ash_strings_gl.xtb
@@ -1896,7 +1896,6 @@
 <translation id="8553395910833293175">Xa se asignou a todos os escritorios.</translation>
 <translation id="8555757996376137129">Quitar escritorio actual</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> recoméndache actualizar o teu dispositivo (<ph name="DEVICE_TYPE" />)</translation>
-<translation id="8563862697512465947">Configuración de notificacións</translation>
 <translation id="8569751806372591456">Aquí tes algunhas suxestións que podes probar</translation>
 <translation id="857201607579416096">O menú moveuse á esquina inferior dereita da pantalla.</translation>
 <translation id="8581946341807941670">Preme <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> e fai clic nunha ligazón</translation>
diff --git a/ash/strings/ash_strings_gu.xtb b/ash/strings/ash_strings_gu.xtb
index 92cdec0..31db47d3 100644
--- a/ash/strings/ash_strings_gu.xtb
+++ b/ash/strings/ash_strings_gu.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">બધા ડેસ્ક માટે પહેલેથી જ સોંપણી કરવામાં આવી છે.</translation>
 <translation id="8555757996376137129">વર્તમાન ડેસ્ક કાઢી નાખો</translation>
 <translation id="856298576161209842">તમે તમારું <ph name="DEVICE_TYPE" /> અપડેટ કરો તેવો <ph name="MANAGER" />નો સુઝાવ છે</translation>
-<translation id="8563862697512465947">નોટિફિકેશન સેટિંગ</translation>
 <translation id="8569751806372591456">અહીં અજમાવવા જેવા અમુક સૂચનો આપવામાં આવ્યા છે</translation>
 <translation id="857201607579416096">મેનૂને સ્ક્રીનની નીચેના જમણા ખૂણામાં ખસેડ્યું.</translation>
 <translation id="8581946341807941670"><ph name="MODIFIER_1" />+<ph name="MODIFIER_2" /> દબાવો અને લિંકને ક્લિક કરો</translation>
diff --git a/ash/strings/ash_strings_hi.xtb b/ash/strings/ash_strings_hi.xtb
index 1bf67f7..a1c8a0f 100644
--- a/ash/strings/ash_strings_hi.xtb
+++ b/ash/strings/ash_strings_hi.xtb
@@ -1889,7 +1889,6 @@
 <translation id="8553395910833293175">सभी डेस्क के लिए पहले से असाइन किया जा चुका है.</translation>
 <translation id="8555757996376137129">मौजूदा डेस्क हटाएं</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> से सुझाव मिला है कि आप अपने <ph name="DEVICE_TYPE" /> को अपडेट करें</translation>
-<translation id="8563862697512465947">सूचना सेटिंग</translation>
 <translation id="8569751806372591456">आज़माने के लिए यहां कुछ सुझाव दिए गए हैं</translation>
 <translation id="857201607579416096">मेन्यू, स्क्रीन के सबसे नीचे दाएं कोने में चला गया है.</translation>
 <translation id="8581946341807941670"><ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> दबाएं और किसी लिंक पर क्लिक करें</translation>
diff --git a/ash/strings/ash_strings_hr.xtb b/ash/strings/ash_strings_hr.xtb
index b3930ac..d93e67d 100644
--- a/ash/strings/ash_strings_hr.xtb
+++ b/ash/strings/ash_strings_hr.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Već je dodijeljeno svim radnim površinama.</translation>
 <translation id="8555757996376137129">Uklanjanje trenutačne radne površine</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> preporučuje da ažurirate svoj uređaj <ph name="DEVICE_TYPE" />.</translation>
-<translation id="8563862697512465947">Postavke obavijesti</translation>
 <translation id="8569751806372591456">Evo nekoliko prijedloga koje možete isprobati</translation>
 <translation id="857201607579416096">Izbornik je premješten u donji desni kut zaslona.</translation>
 <translation id="8581946341807941670">Pritisnite <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> i kliknite vezu</translation>
diff --git a/ash/strings/ash_strings_hu.xtb b/ash/strings/ash_strings_hu.xtb
index 41e2e44..be6734d3 100644
--- a/ash/strings/ash_strings_hu.xtb
+++ b/ash/strings/ash_strings_hu.xtb
@@ -1896,7 +1896,6 @@
 <translation id="8553395910833293175">Már minden asztalhoz hozzá van rendelve.</translation>
 <translation id="8555757996376137129">Jelenlegi asztal eltávolítása</translation>
 <translation id="856298576161209842">A(z) <ph name="MANAGER" /> azt javasolja, hogy frissítse a(z) <ph name="DEVICE_TYPE" /> eszközét.</translation>
-<translation id="8563862697512465947">Értesítési beállítások</translation>
 <translation id="8569751806372591456">Íme néhány javaslat, amelyet érdemes kipróbálni</translation>
 <translation id="857201607579416096">A menü a képernyő jobb alsó sarkába került.</translation>
 <translation id="8581946341807941670">Nyomja le a(z) <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> billentyűkombinációt, majd kattintson a kívánt linkre</translation>
diff --git a/ash/strings/ash_strings_hy.xtb b/ash/strings/ash_strings_hy.xtb
index 98a74a52..69ea6ebd9 100644
--- a/ash/strings/ash_strings_hy.xtb
+++ b/ash/strings/ash_strings_hy.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Արդեն հասանելի է բոլոր աշխատասեղաններին։</translation>
 <translation id="8555757996376137129">Հեռացնել ընթացիկ աշխատասեղանը</translation>
 <translation id="856298576161209842">Կառավարիչը (<ph name="MANAGER" />) խորհուրդ է տալիս, որ թարմացնեք ձեր <ph name="DEVICE_TYPE" /> սարքը։</translation>
-<translation id="8563862697512465947">Ծանուցումների կարգավորումներ</translation>
 <translation id="8569751806372591456">Ահա մի քանի առաջարկ, որոնք կարող եք փորձել</translation>
 <translation id="857201607579416096">Ընտրացանկը տեղափոխվեց էկրանի ներքևի աջ անկյուն։</translation>
 <translation id="8581946341807941670">Սեղմեք <ph name="MODIFIER_1" /><ph name="MODIFIER_2" />, ապա սեղմեք հղման վրա</translation>
diff --git a/ash/strings/ash_strings_id.xtb b/ash/strings/ash_strings_id.xtb
index 94e5c5f..e114e52 100644
--- a/ash/strings/ash_strings_id.xtb
+++ b/ash/strings/ash_strings_id.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Telah ditetapkan ke semua desktop.</translation>
 <translation id="8555757996376137129">Hapus desktop saat ini</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> menyarankan Anda mengupdate <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Setelan Notifikasi</translation>
 <translation id="8569751806372591456">Berikut beberapa saran untuk dicoba</translation>
 <translation id="857201607579416096">Menu dipindahkan ke pojok kanan bawah layar.</translation>
 <translation id="8581946341807941670">Tekan <ph name="MODIFIER_1" /><ph name="MODIFIER_2" />, lalu klik link</translation>
diff --git a/ash/strings/ash_strings_is.xtb b/ash/strings/ash_strings_is.xtb
index 7ac9071..108b375 100644
--- a/ash/strings/ash_strings_is.xtb
+++ b/ash/strings/ash_strings_is.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Þegar úthlutað til allra skrifborða</translation>
 <translation id="8555757996376137129">Fjarlægja núverandi skrifborð</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> mælir með því að þú uppfærir <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Tilkynningastillingar</translation>
 <translation id="8569751806372591456">Hér eru nokkrar tillögur sem þú getur prófað</translation>
 <translation id="857201607579416096">Valmynd færð neðst í hægra horn skjásins.</translation>
 <translation id="8581946341807941670">Ýttu á <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> og smelltu á tengil</translation>
diff --git a/ash/strings/ash_strings_it.xtb b/ash/strings/ash_strings_it.xtb
index 4aa2920..c5bcc7c 100644
--- a/ash/strings/ash_strings_it.xtb
+++ b/ash/strings/ash_strings_it.xtb
@@ -1892,7 +1892,6 @@
 <translation id="8553395910833293175">Finestra già assegnata a tutte le scrivanie.</translation>
 <translation id="8555757996376137129">Rimuovi la scrivania corrente</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> ti consiglia di aggiornare <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Impostazioni di notifica</translation>
 <translation id="8569751806372591456">Ecco alcuni suggerimenti da provare</translation>
 <translation id="857201607579416096">Menu spostato nell'angolo in basso a destra dello schermo.</translation>
 <translation id="8581946341807941670">Premi <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> e fai clic su un link</translation>
diff --git a/ash/strings/ash_strings_iw.xtb b/ash/strings/ash_strings_iw.xtb
index 3aede68..c40c476 100644
--- a/ash/strings/ash_strings_iw.xtb
+++ b/ash/strings/ash_strings_iw.xtb
@@ -18,6 +18,7 @@
 <translation id="1056775291175587022">אין רשתות</translation>
 <translation id="1056898198331236512">אזהרה</translation>
 <translation id="1058009965971887428">שליחת דוח משוב</translation>
+<translation id="1059120031266247284">קובץ ששותף איתך</translation>
 <translation id="1059194134494239015"><ph name="DISPLAY_NAME" />: <ph name="RESOLUTION" /></translation>
 <translation id="1062407476771304334">החלפה</translation>
 <translation id="1073899992769346247">צריך להחליף את הסוללה או לטעון אותה</translation>
@@ -626,6 +627,7 @@
 <translation id="3577473026931028326">משהו השתבש. יש לנסות שוב.</translation>
 <translation id="3580650856351781466">מתבצעת הורדה של קובצי דיבור</translation>
 <translation id="3585296979871889131">הצגת התמונות, המדיה, ההתראות והאפליקציות שבטלפון מהזמן האחרון</translation>
+<translation id="358832729276157756">ExpressKey 1</translation>
 <translation id="3590441166907930941">הלחצן הצדדי</translation>
 <translation id="3593039967545720377">‏כדי להיכנס להיסטוריית הלוח, יש ללחוץ על <ph name="SHORTCUT_KEY_NAME" /> + V לצפייה בלוח. כדי להתחיל, צריך להעתיק פריט.</translation>
 <translation id="3593646411856133110">כדי להציג את האפליקציות הפתוחות, מחליקים כלפי מעלה ולוחצים לחיצה ארוכה</translation>
@@ -642,6 +644,7 @@
 <translation id="3621202678540785336">קלט</translation>
 <translation id="3621712662352432595">הגדרות אודיו</translation>
 <translation id="3626281679859535460">בהירות</translation>
+<translation id="3628323833346754646">הלחצן הקדמי</translation>
 <translation id="3630697955794050612">כבויה</translation>
 <translation id="3631369015426612114">המקורות הבאים יכולים להציג התראות</translation>
 <translation id="3633097874324966332">‏צריך לפתוח את הגדרות Bluetooth כדי להתאים את המכשיר</translation>
@@ -1283,6 +1286,7 @@
 <translation id="6052614013050385269">לחיצה ימנית על קישור</translation>
 <translation id="6054305421211936131">כניסה באמצעות כרטיס חכם</translation>
 <translation id="6059276912018042191">‏כרטיסיות Chrome אחרונות</translation>
+<translation id="606147842285839995">ExpressKey 3</translation>
 <translation id="6062360702481658777">תבוצע יציאה באופן אוטומטי בעוד <ph name="LOGOUT_TIME_LEFT" />.</translation>
 <translation id="6064463340679478396">סיימתי להשתמש בקובץ</translation>
 <translation id="6068258534237496331">פקדים לשיחות וידאו</translation>
@@ -1344,6 +1348,7 @@
 <translation id="6309219492973062892">לחיצה או הקשה על הסמלים 1-8 במדף</translation>
 <translation id="6315170314923504164">קול</translation>
 <translation id="6319058840130157106">מעבר אחורה בין הפינה השמאלית התחתונה, מרכז האפליקציות, סרגל הכתובות, סרגל הסימניות, האתר שפתוח וההורדות</translation>
+<translation id="6319503618073410818">לצפייה בפרטים בדפדפן</translation>
 <translation id="6324916366299863871">עריכת קיצור דרך</translation>
 <translation id="6330012934079202188">מוצגים החלונות מכל שולחנות העבודה הווירטואליים. ניתן להקיש על מקש החץ למעלה כדי להציג את החלונות משולחן העבודה הווירטואלי הנוכחי</translation>
 <translation id="6338485349199627913"><ph name="DISPLAY_NAME" /> הוא סשן מנוהל שמנוהל על ידי <ph name="MANAGER" /></translation>
@@ -1564,6 +1569,7 @@
 <translation id="7229029500464092426">זיכרון פנוי: <ph name="AVAILABLE_MEMORY" /> | סה"כ: <ph name="TOTAL_MEMORY" /></translation>
 <translation id="7244725679040769470">רמת הטעינה שנותרה בסוללה: %<ph name="PERCENTAGE" />. צריך לחבר את המכשיר למקור חשמל.</translation>
 <translation id="7246071203293827765">‏<ph name="UPDATE_TEXT" />. יש להפעיל את ה-Chromebook מחדש כדי להחיל עדכון. התהליך עשוי להימשך עד דקה אחת.</translation>
+<translation id="7256057185598509352">ExpressKey 2</translation>
 <translation id="7256634071279256947">מיקרופון אחורי</translation>
 <translation id="7258828758145722155">נערך אתמול</translation>
 <translation id="726276584504105859">לשימוש במסך מפוצל יש לגרור לכאן</translation>
@@ -1693,6 +1699,7 @@
 <translation id="7742327441377685481">אין התראות</translation>
 <translation id="7748275671948949022">הדגשת הלחצן של מרכז האפליקציות במדף</translation>
 <translation id="7749443890790263709">הגעת למספר המקסימלי של שולחנות עבודה.</translation>
+<translation id="7749958366403230681">ExpressKey 4</translation>
 <translation id="776344839111254542">יש ללחוץ כדי להציג את פרטי העדכון</translation>
 <translation id="7768784765476638775">הקראה</translation>
 <translation id="7769299611924763557">‏קובץ ה-GIF יהיה מוכן בקרוב</translation>
@@ -1890,7 +1897,6 @@
 <translation id="8553395910833293175">כבר מוקצה לכל שולחנות העבודה הווירטואליים.</translation>
 <translation id="8555757996376137129">הסרת שולחן העבודה הווירטואלי הנוכחי</translation>
 <translation id="856298576161209842">לפי ההמלצה של <ph name="MANAGER" />, כדאי לעדכן את ה-<ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">הגדרות התראה</translation>
 <translation id="8569751806372591456">הנה כמה הצעות שכדאי לנסות</translation>
 <translation id="857201607579416096">התפריט הועבר לפינה השמאלית התחתונה של המסך.</translation>
 <translation id="8581946341807941670">הקשה על <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> ולחיצה על קישור</translation>
@@ -2020,6 +2026,7 @@
 <translation id="9098969848082897657">השתקת הטלפון</translation>
 <translation id="9121941381564890244"><ph name="SNIP" /> או <ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT" /><ph name="SEPARATOR2" /><ph name="OVERVIEW" /></translation>
 <translation id="9126339866969410112">ביטול הפעולה האחרונה</translation>
+<translation id="9129245940793250979">הלחצן האחורי</translation>
 <translation id="9133335900048457298">לא ניתן להקליט תוכן מוגן</translation>
 <translation id="9139720510312328767">מחיקת האות הבאה</translation>
 <translation id="9151906066336345901">‏מקש End</translation>
diff --git a/ash/strings/ash_strings_ja.xtb b/ash/strings/ash_strings_ja.xtb
index dd079399..88c26f4 100644
--- a/ash/strings/ash_strings_ja.xtb
+++ b/ash/strings/ash_strings_ja.xtb
@@ -1896,7 +1896,6 @@
 <translation id="8553395910833293175">すべてのデスクに割り当て済みです。</translation>
 <translation id="8555757996376137129">現在のデスクを削除する</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> が <ph name="DEVICE_TYPE" /> を更新するよう推奨しています</translation>
-<translation id="8563862697512465947">通知設定</translation>
 <translation id="8569751806372591456">新しい検索候補をお試しください</translation>
 <translation id="857201607579416096">メニューは画面右下に移動しました。</translation>
 <translation id="8581946341807941670"><ph name="MODIFIER_1" />+<ph name="MODIFIER_2" /> キーを押しながらリンクをクリックする</translation>
diff --git a/ash/strings/ash_strings_ka.xtb b/ash/strings/ash_strings_ka.xtb
index 8f2705a..0ce118f 100644
--- a/ash/strings/ash_strings_ka.xtb
+++ b/ash/strings/ash_strings_ka.xtb
@@ -358,6 +358,7 @@
 <translation id="2484513351006226581">კლავიატურის განლაგების გადასართველად გამოიყენეთ კლავიშთა კომბინაცია: <ph name="KEYBOARD_SHORTCUT" />.</translation>
 <translation id="2486214324139475545"><ph name="DESK_NAME" />-ის გადასახედი ვერსია. აქტიური სამუშაო მაგიდა.</translation>
 <translation id="2487915095798731898">გაწევრიანება</translation>
+<translation id="2499445554382787206">სამუშაო მაგიდის პროფილის მენიუ. <ph name="DESK_NAME" /></translation>
 <translation id="2501920221385095727">კლავიშების ფიქსაცია</translation>
 <translation id="2504454902900101003">თქვენი ტელეფონის ბოლოდროინდელი ფოტოების, მედიაფაილებისა და შეტყობინებების ნახვის დაყენების დახურვა</translation>
 <translation id="2509468283778169019">CAPS LOCK ჩართულია</translation>
@@ -604,6 +605,7 @@
 <translation id="3509391053705095206">თქვენი ტელეფონი ვერ მოიძებნა. დარწმუნდით, რომ თქვენს ტელეფონზე ჩართულია Bluetooth.</translation>
 <translation id="3510164367642747937">მაუსის კურსორის გამოყოფა</translation>
 <translation id="3513798432020909783">ანგარიშს მართავს <ph name="MANAGER_EMAIL" /></translation>
+<translation id="3517037892157925473">ამოცანების ბოლო განახლება: <ph name="TIME" />, <ph name="DATE" />.</translation>
 <translation id="352245152354538528">{0,plural, =1{განაახლეთ მოწყობილობა 1 წუთის განმავლობაში}other{განაახლეთ მოწყობილობა # წუთის განმავლობაში}}</translation>
 <translation id="3522979239100719575">იძებნება ხელმისაწვდომი პროფილები. ამას შეიძლება რამდენიმე წუთი დასჭირდეს.</translation>
 <translation id="3526440770046466733">ბმულის გახსნა ახალ ჩანართზე და მიმდინარე ჩანართზე დარჩენა</translation>
@@ -1142,6 +1144,7 @@
 <translation id="5536723544185013515">ბოლოდროინდელი აპები, ყველა ბოლოდროინდელ აპზე წვდომისთვის გამოიყენეთ კლავიში მარცხნივ ან მარჯვნივ მიმართული ისრით</translation>
 <translation id="553675580533261935">მიმდინარეობს სესიიდან გამოსვლა</translation>
 <translation id="5537725057119320332">მაუწყებლობა</translation>
+<translation id="554017492391497564">დასრულებულად ვერ მოინიშნა.</translation>
 <translation id="5546397813406633847">მომხმარებლის აღდგენა</translation>
 <translation id="554893713779400387">კარნახის გადართვა</translation>
 <translation id="5550417424894892620">ჩავლებით გადაიტანეთ ფაილები დესკტოპზე, ისინი <ph name="HOLDING_SPACE_TITLE" />-ს რომ დაამატოთ. ფაილებს დესკტოპს ვერ დაამატებთ.</translation>
@@ -1336,6 +1339,7 @@
 <translation id="6237231532760393653">1X</translation>
 <translation id="62380141479352646">ბატარეა იცლება. ბატარეის დამზოგველი ჩართულია.</translation>
 <translation id="6247728804802644171">შეტყობინებების გახსნა</translation>
+<translation id="6249795363855770621">დასრულებულად ვერ მოინიშნა. ცადეთ ხელახლა, როცა ონლაინ იქნებით.</translation>
 <translation id="6254629735336163724">ჩაკეტილია ჰორიზონტალურზე</translation>
 <translation id="6259254695169772643">ასარჩევად ისარგებლეთ სტილუსით</translation>
 <translation id="6267036997247669271"><ph name="NAME" />: გააქტიურება…</translation>
@@ -1496,6 +1500,7 @@
 <translation id="6896758677409633944">კოპირება</translation>
 <translation id="6912841030378044227">მისამართთა ზოლის ფოკუსში მოქცევა</translation>
 <translation id="6912901278692845878">სწრაფი ტური</translation>
+<translation id="6917259695595127329">ამოცანების ბოლო განახლება <ph name="TIME" />.</translation>
 <translation id="6919251195245069855">თქვენი სმარტ-ბარათის ამოცნობა ვერ მოხერხდა. ცადეთ ხელახლა.</translation>
 <translation id="692135145298539227">წაშლა</translation>
 <translation id="6929081673585394903">მართვის საშუალებების ჩვენება</translation>
@@ -1895,7 +1900,6 @@
 <translation id="8553395910833293175">უკვე მიმაგრებულია ყველა სამუშაო მაგიდაზე.</translation>
 <translation id="8555757996376137129">ამჟამინდელი სამუშაო მაგიდის წაშლა</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> გირჩევთ, განაახლოთ თქვენი <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">შეტყობინების პარამეტრები</translation>
 <translation id="8569751806372591456">აი, რამდენიმე საცდელი შემოთავაზება</translation>
 <translation id="857201607579416096">მენიუ გადატანილია ეკრანის ქვედა მარჯვენა კუთხეში.</translation>
 <translation id="8581946341807941670">დაჭერით აირჩიეთ <ph name="MODIFIER_1" /><ph name="MODIFIER_2" />, შემდეგ კი დააწკაპუნეთ ბმულზე</translation>
diff --git a/ash/strings/ash_strings_kk.xtb b/ash/strings/ash_strings_kk.xtb
index 4034ee8..c2183c1 100644
--- a/ash/strings/ash_strings_kk.xtb
+++ b/ash/strings/ash_strings_kk.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Барлық жұмыс үстеліне әлдеқашан тағайындалған.</translation>
 <translation id="8555757996376137129">Ағымдағы жұмыс үстелін өшіру</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> сізге <ph name="DEVICE_TYPE" /> құрылғысын жаңартуды ұсынады.</translation>
-<translation id="8563862697512465947">Хабарландыру параметрлері</translation>
 <translation id="8569751806372591456">Мұнда ұсыныстар берілген</translation>
 <translation id="857201607579416096">Мәзір экранның төменгі оң жақ бұрышына жылжытылды.</translation>
 <translation id="8581946341807941670"><ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> пернесін басып, сілтемені түртіңіз</translation>
diff --git a/ash/strings/ash_strings_km.xtb b/ash/strings/ash_strings_km.xtb
index fe85d772..a6cc425 100644
--- a/ash/strings/ash_strings_km.xtb
+++ b/ash/strings/ash_strings_km.xtb
@@ -358,6 +358,7 @@
 <translation id="2484513351006226581">ចុច <ph name="KEYBOARD_SHORTCUT" /> ដើម្បី​ប្តូរប្លង់​ក្តារ​ចុច។</translation>
 <translation id="2486214324139475545">ការមើល <ph name="DESK_NAME" /> សាកល្បង។ តុ​សកម្ម។</translation>
 <translation id="2487915095798731898">ចូលរួម</translation>
+<translation id="2499445554382787206">ម៉ឺនុយ​កម្រងព័ត៌មាន​តុ។ <ph name="DESK_NAME" /></translation>
 <translation id="2501920221385095727">គ្រាប់ចុចស្អិត</translation>
 <translation id="2504454902900101003">ច្រានចោល​ការរៀបចំ​ការមើល​រូបថត មេឌៀ និង​ការជូនដំណឹង​ថ្មីៗ​លើ​ទូរសព្ទ​របស់​អ្នក</translation>
 <translation id="2509468283778169019">CAPS LOCK ត្រូវបានបើក</translation>
@@ -604,6 +605,7 @@
 <translation id="3509391053705095206">រកទូរសព្ទរបស់អ្នក​មិនឃើញទេ។ សូមប្រាកដ​ថាបាន​បើកប៊្លូធូស​ទូរសព្ទ​របស់​អ្នក។</translation>
 <translation id="3510164367642747937">រំលេច​ទស្សន៍ទ្រនិច​កណ្ដុរ</translation>
 <translation id="3513798432020909783">គណនី​ស្ថិត​ក្រោមការគ្រប់គ្រង​របស់ <ph name="MANAGER_EMAIL" /></translation>
+<translation id="3517037892157925473">បានធ្វើបច្ចុប្បន្នភាព​កិច្ចការ​ចុងក្រោយ៖ <ph name="TIME" /> <ph name="DATE" />។</translation>
 <translation id="352245152354538528">{0,plural, =1{ដំឡើងកំណែ​ឧបករណ៍​ក្នុងរយៈពេល 1 នាទី​}other{ដំឡើងកំណែ​ឧបករណ៍​ក្នុងរយៈពេល # នាទី​}}</translation>
 <translation id="3522979239100719575">កំពុងរកមើល​កម្រងព័ត៌មាន​ដែលអាចប្រើបាន។ សកម្មភាពនេះ​អាចចំណាយ​ពេលពីរបីនាទី។</translation>
 <translation id="3526440770046466733">បើក​តំណ​នៅ​ក្នុង​ផ្ទាំង​ថ្មី រួច​បន្ត​នៅ​ក្នុង​ផ្ទាំង​បច្ចុប្បន្ន</translation>
@@ -1142,6 +1144,7 @@
 <translation id="5536723544185013515">កម្មវិធីថ្មីៗ, រុករកដោយប្រើគ្រាប់ចុចព្រួញទៅ​ឆ្វេង ឬ​ទៅ​ស្ដាំ ដើម្បីចូលប្រើប្រាស់​កម្មវិធីថ្មីៗទាំងអស់</translation>
 <translation id="553675580533261935">ការ​ចាកចេញ​ពី​សម័យ</translation>
 <translation id="5537725057119320332">ខាស</translation>
+<translation id="554017492391497564">មិនអាច​សម្គាល់ថា​បានបញ្ចប់​បានទេ។</translation>
 <translation id="5546397813406633847">ស្ដារអ្នកប្រើប្រាស់ឡើងវិញ</translation>
 <translation id="554893713779400387">បិទ/បើក​ការសរសេរតាមអាន</translation>
 <translation id="5550417424894892620">ទម្លាក់​ឯកសារ​នៅលើ​អេក្រង់ដើម ដើម្បី​បញ្ចូល​ឯកសារ​ទាំងនោះ​ទៅ <ph name="HOLDING_SPACE_TITLE" />។ អ្នក​មិនអាច​បញ្ចូលឯកសារ​ទៅ​អេក្រង់ដើម​បានទេ។</translation>
@@ -1336,6 +1339,7 @@
 <translation id="6237231532760393653">1X</translation>
 <translation id="62380141479352646">ថ្មសល់តិច។ បានបើក​មុខងារ​សន្សំថ្ម។</translation>
 <translation id="6247728804802644171">បើក​ការ​ជូន​ដំណឹង</translation>
+<translation id="6249795363855770621">មិនអាច​សម្គាល់ថា​បានបញ្ចប់​បានទេ។ សូមព្យាយាម​ម្ដងទៀត នៅពេលមាន​អ៊ីនធឺណិត។</translation>
 <translation id="6254629735336163724">បាន​ចាក់សោ​ឱ្យ​ស្ថិត​ក្នុងទិសដៅផ្ដេក</translation>
 <translation id="6259254695169772643">ប្រើប៊ិច​របស់អ្នក​ដើម្បី​ជ្រើសរើស</translation>
 <translation id="6267036997247669271"><ph name="NAME" />: កំពុងធ្វើសកម្មភាព...</translation>
@@ -1496,6 +1500,7 @@
 <translation id="6896758677409633944">ចម្លង</translation>
 <translation id="6912841030378044227">ផ្ដោតលើ​របារ​អាសយដ្ឋាន</translation>
 <translation id="6912901278692845878">ណែនាំ​បង្ហាញ​ត្រួសៗ</translation>
+<translation id="6917259695595127329">បានធ្វើបច្ចុប្បន្នភាព​កិច្ចការ​ចុងក្រោយ៖ <ph name="TIME" />។</translation>
 <translation id="6919251195245069855">មិន​ស្គាល់​កាត​ឆ្លាតវៃរបស់អ្នកទេ។ សូមព្យាយាមម្ដងទៀត។</translation>
 <translation id="692135145298539227">លុប</translation>
 <translation id="6929081673585394903">បង្ហាញ​ការគ្រប់គ្រង</translation>
@@ -1894,7 +1899,6 @@
 <translation id="8553395910833293175">បានកំណត់​ទៅតុទាំងអស់​រួចហើយ។</translation>
 <translation id="8555757996376137129">ដកតុ​បច្ចុប្បន្នចេញ</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> ណែនាំឱ្យអ្នក​ដំឡើងកំណែ <ph name="DEVICE_TYPE" /> របស់អ្នក</translation>
-<translation id="8563862697512465947">​កំណត់​ការ​ជូន​ដំណឹង</translation>
 <translation id="8569751806372591456">ទាំងនេះជាការណែនាំមួយចំនួនសម្រាប់សាកល្បង</translation>
 <translation id="857201607579416096">ម៉ឺនុយ​ត្រូវបានផ្លាស់ទី​ទៅ​ជ្រុងខាងក្រោម​ផ្នែកខាងស្ដាំ​នៃអេក្រង់​។</translation>
 <translation id="8581946341807941670">ចុច <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> រួចចុចតំណ</translation>
diff --git a/ash/strings/ash_strings_kn.xtb b/ash/strings/ash_strings_kn.xtb
index d8081f96..5969263 100644
--- a/ash/strings/ash_strings_kn.xtb
+++ b/ash/strings/ash_strings_kn.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">ಈಗಾಗಲೇ ಎಲ್ಲಾ ಡೆಸ್ಕ್‌ಗಳಿಗೆ ನಿಯೋಜಿಸಲಾಗಿದೆ.</translation>
 <translation id="8555757996376137129">ಪ್ರಸ್ತುತ ಡೆಸ್ಕ್ ಅನ್ನು ತೆಗೆದುಹಾಕಿ</translation>
 <translation id="856298576161209842">ಈ ನಿಮ್ಮ <ph name="DEVICE_TYPE" /> ಅನ್ನು ಅಪ್‌ಡೇಟ್ ಮಾಡಲು <ph name="MANAGER" /> ಶಿಫಾರಸು ಮಾಡುತ್ತದೆ</translation>
-<translation id="8563862697512465947">ಸೂಚನೆ  ಸೆಟ್ಟಿಂಗ್‌ಗಳು</translation>
 <translation id="8569751806372591456">ಪ್ರಯತ್ನಿಸಲು ಕೆಲವು ಸಲಹೆಗಳು ಇಲ್ಲಿವೆ</translation>
 <translation id="857201607579416096">ಮೆನುವನ್ನು ಪರದೆಯ ಕೆಳಭಾಗದಲ್ಲಿ ಬಲತುದಿಗೆ ಸರಿಸಲಾಗಿದೆ.</translation>
 <translation id="8581946341807941670"><ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> ಒತ್ತಿರಿ ಮತ್ತು ಲಿಂಕ್‌ ಅನ್ನು ಕ್ಲಿಕ್‌ ಮಾಡಿ</translation>
diff --git a/ash/strings/ash_strings_ko.xtb b/ash/strings/ash_strings_ko.xtb
index ef33442..837e490f 100644
--- a/ash/strings/ash_strings_ko.xtb
+++ b/ash/strings/ash_strings_ko.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">이미 모든 데스크에 할당되어 있습니다.</translation>
 <translation id="8555757996376137129">현재 데스크를 삭제합니다.</translation>
 <translation id="856298576161209842"><ph name="MANAGER" />에서 <ph name="DEVICE_TYPE" /> 기기의 업데이트를 권장합니다.</translation>
-<translation id="8563862697512465947">알림 설정</translation>
 <translation id="8569751806372591456">다음은 몇 가지 제안사항입니다.</translation>
 <translation id="857201607579416096">메뉴가 화면 오른쪽 하단으로 이동했습니다.</translation>
 <translation id="8581946341807941670"><ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> 키를 누른 상태에서 링크 클릭</translation>
diff --git a/ash/strings/ash_strings_ky.xtb b/ash/strings/ash_strings_ky.xtb
index 3be2d832..a5eaf61 100644
--- a/ash/strings/ash_strings_ky.xtb
+++ b/ash/strings/ash_strings_ky.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Бардык иш такталар дайындалган.</translation>
 <translation id="8555757996376137129">Учурдагы иш тактаны өчүрүү</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> <ph name="DEVICE_TYPE" /> түзмөгүңүздү жаңыртууну сунуштайт</translation>
-<translation id="8563862697512465947">Билдирмелердин параметрлери</translation>
 <translation id="8569751806372591456">Төмөнкү сунуштарды байкап көрүңүз:</translation>
 <translation id="857201607579416096">Меню экрандын төмөнкү оң бурчуна жылдырылды.</translation>
 <translation id="8581946341807941670"><ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> баскычтарын басып, шилтемени чыкылдатыңыз</translation>
diff --git a/ash/strings/ash_strings_lo.xtb b/ash/strings/ash_strings_lo.xtb
index 97b2e5e..b6d41d6 100644
--- a/ash/strings/ash_strings_lo.xtb
+++ b/ash/strings/ash_strings_lo.xtb
@@ -358,6 +358,7 @@
 <translation id="2484513351006226581">ແຕະ <ph name="KEYBOARD_SHORTCUT" /> ເພື່ອປ່ຽນໂຄງຮ່າງແປ້ນພິມ.</translation>
 <translation id="2486214324139475545">ຕົວຢ່າງ <ph name="DESK_NAME" />. ໂຕະທີ່ໃຊ້ຢູ່.</translation>
 <translation id="2487915095798731898">ເຂົ້າຮ່ວມ</translation>
+<translation id="2499445554382787206">ເມນູໂປຣໄຟລ໌ໂຕະ. <ph name="DESK_NAME" /></translation>
 <translation id="2501920221385095727">ປຸ່ມສະຕິກກີ້</translation>
 <translation id="2504454902900101003">ປິດການຕັ້ງຄ່າການເບິ່ງຮູບພາບຫຼ້າສຸດ, ມີເດຍ ແລະ ການແຈ້ງເຕືອນຢູ່ໂທລະສັບຂອງທ່ານໄວ້</translation>
 <translation id="2509468283778169019">CAPS LOCK ເປີດຢູ່</translation>
@@ -604,6 +605,7 @@
 <translation id="3509391053705095206">ບໍ່ສາມາດຊອກເຫັນໂທລະສັບຂອງທ່ານໄດ້. ກະລຸນາກວດສອບວ່າ Bluetooth ຂອງໂທລະສັບທ່ານເປີດຢູ່.</translation>
 <translation id="3510164367642747937">ໝາຍເຄີເຊີເມົ້າ</translation>
 <translation id="3513798432020909783">ບັນຊີທີ່ຈັດການໂດຍ <ph name="MANAGER_EMAIL" /></translation>
+<translation id="3517037892157925473">ອັບເດດໜ້າວຽກຫຼ້າສຸດ: <ph name="TIME" />, <ph name="DATE" />.</translation>
 <translation id="352245152354538528">{0,plural, =1{ອັບເດດອຸປະກອນພາຍໃນ 1 ນາທີ}other{ອັບເດດອຸປະກອນພາຍໃນ # ນາທີ}}</translation>
 <translation id="3522979239100719575">ກຳລັງຊອກຫາໂປຣໄຟລ໌ທີ່ສາມາດໃຊ້ໄດ້. ຂັ້ນຕອນນີ້ອາດໃຊ້ເວລາສອງສາມນາທີ.</translation>
 <translation id="3526440770046466733">ເປີດລິ້ງໃນແຖບໃໝ່ ແລະ ຢູ່ໃນແຖບປັດຈຸບັນຕໍ່ໄປ</translation>
@@ -1142,6 +1144,7 @@
 <translation id="5536723544185013515">ແອັບຫຼ້າສຸດ, ນຳທາງດ້ວຍປຸ່ມລູກສອນຊ້າຍ ຫຼື ຂວາເພື່ອເຂົ້າເຖິງແອັບຫຼ້າສຸດທັງໝົດ</translation>
 <translation id="553675580533261935">ກໍາລັງອອກຈາກເຊດຊັນ</translation>
 <translation id="5537725057119320332">ຄາສທ໌</translation>
+<translation id="554017492391497564">ບໍ່ສາມາດໝາຍເປັນສຳເລັດໄດ້.</translation>
 <translation id="5546397813406633847">ກູ້ຜູ້ໃຊ້ຄືນມາ</translation>
 <translation id="554893713779400387">ເປີດປິດການຂຽນຕາມຄຳບອກ</translation>
 <translation id="5550417424894892620">ວາງໄຟລ໌ຢູ່ເດັສທັອບເພື່ອເພີ່ມພວກມັນໄປໃສ່ <ph name="HOLDING_SPACE_TITLE" />. ທ່ານບໍ່ສາມາດເພີ່ມໄຟລ໌ນີ້ໄປໃສ່ເດັສທັອບໄດ້.</translation>
@@ -1336,6 +1339,7 @@
 <translation id="6237231532760393653">1X</translation>
 <translation id="62380141479352646">ແບັດເຕີຣີເຫຼືອໜ້ອຍ. ເປີດໃຊ້ຕົວປະຢັດແບັດເຕີຣີແລ້ວ.</translation>
 <translation id="6247728804802644171">ເປີດການແຈ້ງເຕືອນ</translation>
+<translation id="6249795363855770621">ບໍ່ສາມາດໝາຍເປັນສຳເລັດໄດ້. ກະລຸນາລອງໃໝ່ເມື່ອອອນລາຍ.</translation>
 <translation id="6254629735336163724">ລັອກເປັນລວງນອນ</translation>
 <translation id="6259254695169772643">ໃຊ້ປາຍປາກກາຂອງທ່ານເພື່ອເລືອກ</translation>
 <translation id="6267036997247669271"><ph name="NAME" />: ກຳລັງເປີດນຳໃຊ້...</translation>
@@ -1496,6 +1500,7 @@
 <translation id="6896758677409633944">ກັອບປີ້</translation>
 <translation id="6912841030378044227">ເນັ້ນໃສ່ແຖບທີ່ຢູ່</translation>
 <translation id="6912901278692845878">ການທົວສັ້ນໆ</translation>
+<translation id="6917259695595127329">ອັບເດດໜ້າວຽກຫຼ້າສຸດ: <ph name="TIME" />.</translation>
 <translation id="6919251195245069855">ບໍ່ສາມາດຮັບຮູ້ບັດອັດສະລິຍະຂອງທ່ານໄດ້. ລອງໃໝ່.</translation>
 <translation id="692135145298539227">ລຶບ</translation>
 <translation id="6929081673585394903">ສະແດງການຄວບຄຸມ</translation>
@@ -1895,7 +1900,6 @@
 <translation id="8553395910833293175">ມອບໝາຍໃຫ້ໂຕະທັງໝົດແລ້ວ.</translation>
 <translation id="8555757996376137129">ລຶບໂຕະປັດຈຸບັນອອກ</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> ແນະນຳໃຫ້ທ່ານອັບເດດ <ph name="DEVICE_TYPE" /> ຂອງທ່ານ</translation>
-<translation id="8563862697512465947">ການຕັ້ງຄ່າການແຈ້ງເຕືອນ</translation>
 <translation id="8569751806372591456">ນີ້ແມ່ນການແນະນຳບາງຢ່າງໃຫ້ລອງ</translation>
 <translation id="857201607579416096">ຍ້າຍເມນູໄປແຈລຸ່ມສຸດເບື້ອງຂວາຂອງໜ້າຈໍ.</translation>
 <translation id="8581946341807941670">ກົດ <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> ແລ້ວຄລິກລິ້ງ</translation>
diff --git a/ash/strings/ash_strings_lt.xtb b/ash/strings/ash_strings_lt.xtb
index cfc5a51..6664e1b 100644
--- a/ash/strings/ash_strings_lt.xtb
+++ b/ash/strings/ash_strings_lt.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Jau priskirta visiems darbalaukiams.</translation>
 <translation id="8555757996376137129">Pašalinti dabartinį darbalaukį</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> rekomenduoja atnaujinti „<ph name="DEVICE_TYPE" />“</translation>
-<translation id="8563862697512465947">Pranešimų nustatymai</translation>
 <translation id="8569751806372591456">Štai keli pasiūlymai, kuriuos galite išbandyti</translation>
 <translation id="857201607579416096">Meniu perkeltas į apatinį dešinįjį ekrano kampą.</translation>
 <translation id="8581946341807941670">Paspauskite <ph name="MODIFIER_1" /> <ph name="MODIFIER_2" /> ir spustelėkite nuorodą</translation>
diff --git a/ash/strings/ash_strings_lv.xtb b/ash/strings/ash_strings_lv.xtb
index 86ab6b6d..e80edb3 100644
--- a/ash/strings/ash_strings_lv.xtb
+++ b/ash/strings/ash_strings_lv.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Jau ir redzams visās darbvietās.</translation>
 <translation id="8555757996376137129">Noņemt pašreizējo darbvietu</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> iesaka atjaunināt ierīci <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Paziņojumu iestatījumi</translation>
 <translation id="8569751806372591456">Tālāk ir sniegti daži ieteikumi, ko varat izmēģināt</translation>
 <translation id="857201607579416096">Izvēlne pārvietota uz ekrāna apakšējo kreiso malu.</translation>
 <translation id="8581946341807941670">Nospiediet <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> un noklikšķiniet uz saites</translation>
diff --git a/ash/strings/ash_strings_mk.xtb b/ash/strings/ash_strings_mk.xtb
index 028402c..824f32f 100644
--- a/ash/strings/ash_strings_mk.xtb
+++ b/ash/strings/ash_strings_mk.xtb
@@ -1896,7 +1896,6 @@
 <translation id="8553395910833293175">Веќе е назначено на сите работни површини.</translation>
 <translation id="8555757996376137129">Отстранете ја тековната работна површина</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> препорачува да го ажурирате вашиот <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Поставки за известувања</translation>
 <translation id="8569751806372591456">Еве неколку предлози за да испробате</translation>
 <translation id="857201607579416096">Менито е преместено во долниот десен агол на екранот.</translation>
 <translation id="8581946341807941670">Притиснете <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> и кликнете на линк</translation>
diff --git a/ash/strings/ash_strings_ml.xtb b/ash/strings/ash_strings_ml.xtb
index 35c8758..ae9d6688 100644
--- a/ash/strings/ash_strings_ml.xtb
+++ b/ash/strings/ash_strings_ml.xtb
@@ -1896,7 +1896,6 @@
 <translation id="8553395910833293175">എല്ലാ ഡെസ്ക്കുകൾക്കും ഇതിനകം അസൈൻ ചെയ്‌തിട്ടുണ്ട്.</translation>
 <translation id="8555757996376137129">നിലവിലെ ഡെസ്‌ക് നീക്കം ചെയ്യുക</translation>
 <translation id="856298576161209842">നിങ്ങളുടെ <ph name="DEVICE_TYPE" /> അപ്‌ഡേറ്റ് ചെയ്യാൻ <ph name="MANAGER" /> നിർദ്ദേശിക്കുന്നു.</translation>
-<translation id="8563862697512465947">വിജ്ഞാപന ക്രമീകരണങ്ങള്‍‌</translation>
 <translation id="8569751806372591456">പരീക്ഷിക്കാവുന്ന ചില നിർദ്ദേശങ്ങൾ ഇതാ</translation>
 <translation id="857201607579416096">സ്‌ക്രീനിന്റെ ചുവടെ വലത് കോണിലേക്ക് മെനു നീക്കിയിരിക്കുന്നു.</translation>
 <translation id="8581946341807941670"><ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> അമർത്തി ഒരു ലിങ്ക് ക്ലിക്ക് ചെയ്യുക</translation>
diff --git a/ash/strings/ash_strings_mn.xtb b/ash/strings/ash_strings_mn.xtb
index f744ab2b..dcafd6a 100644
--- a/ash/strings/ash_strings_mn.xtb
+++ b/ash/strings/ash_strings_mn.xtb
@@ -1897,7 +1897,6 @@
 <translation id="8553395910833293175">Бүх дэлгэц дээр аль хэдийн оноосон.</translation>
 <translation id="8555757996376137129">Одоогийн цонхыг хасах</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> танд өөрийн <ph name="DEVICE_TYPE" />-г шинэчлэхийг зөвлөж байна</translation>
-<translation id="8563862697512465947">Мэдэгдлийн тохиргоо</translation>
 <translation id="8569751806372591456">Оролдож үзэх цөөн хэдэн зөвлөмж энд байна</translation>
 <translation id="857201607579416096">Цэсийг дэлгэцийн баруун доод булан руу зөөсөн.</translation>
 <translation id="8581946341807941670"><ph name="MODIFIER_1" /><ph name="MODIFIER_2" />-г дараад холбоосыг товшино уу</translation>
diff --git a/ash/strings/ash_strings_mr.xtb b/ash/strings/ash_strings_mr.xtb
index 03e09b0..79234e2 100644
--- a/ash/strings/ash_strings_mr.xtb
+++ b/ash/strings/ash_strings_mr.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">सर्व डेस्कना आधीपासून असाइन केले आहे.</translation>
 <translation id="8555757996376137129">सध्याचा डेस्क काढून टाका</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> तुम्हाला तुमचे <ph name="DEVICE_TYPE" /> अपडेट करण्याची शिफारस करतो</translation>
-<translation id="8563862697512465947">सूचना सेटिंग्ज</translation>
 <translation id="8569751806372591456">वापरून पाहण्यासाठी या काही सूचना आहेत</translation>
 <translation id="857201607579416096">मेनू स्क्रीनच्या तळाशी उजव्या कोपर्‍यात हलवला.</translation>
 <translation id="8581946341807941670"><ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> प्रेस करा आणि लिंकवर क्लिक करा</translation>
diff --git a/ash/strings/ash_strings_ms.xtb b/ash/strings/ash_strings_ms.xtb
index 7edc482..120de70 100644
--- a/ash/strings/ash_strings_ms.xtb
+++ b/ash/strings/ash_strings_ms.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Telah pun diuntukkan kepada semua meja.</translation>
 <translation id="8555757996376137129">Alih keluar meja semasa</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> mengesyorkan supaya anda mengemas kini <ph name="DEVICE_TYPE" /> anda</translation>
-<translation id="8563862697512465947">Tetapan Pemberitahuan</translation>
 <translation id="8569751806372591456">Yang berikut ialah beberapa cadangan untuk dicuba</translation>
 <translation id="857201607579416096">Menu dialihkan ke sudut bawah sebelah kanan skrin.</translation>
 <translation id="8581946341807941670">Tekan <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> dan klik pautan</translation>
diff --git a/ash/strings/ash_strings_my.xtb b/ash/strings/ash_strings_my.xtb
index 7a77dac6..0dd9a09 100644
--- a/ash/strings/ash_strings_my.xtb
+++ b/ash/strings/ash_strings_my.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">မျက်နှာပြင်နေရာအားလုံးတွင် သတ်မှတ်ပြီးပါပြီ။</translation>
 <translation id="8555757996376137129">လက်ရှိမျက်နှာပြင် ဖယ်ရှားရန်</translation>
 <translation id="856298576161209842">သင့် <ph name="DEVICE_TYPE" /> ကိုအပ်ဒိတ်လုပ်ရန် <ph name="MANAGER" /> ကအကြံပြုသည်</translation>
-<translation id="8563862697512465947">အကြောင်းကြားချက် ဆက်တင်များ</translation>
 <translation id="8569751806372591456">စမ်းလုပ်နိုင်သော အကြံပြုချက်အချို့ကို ပြထားသည်</translation>
 <translation id="857201607579416096">မီနူးကို ဖန်သားပြင်၏ ညာဘက်အောက်ခြေထောင့်သို့ ရွှေ့လိုက်သည်။</translation>
 <translation id="8581946341807941670"><ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> ကိုဖိပြီး လင့်ခ်ကို နှိပ်ပါ</translation>
diff --git a/ash/strings/ash_strings_ne.xtb b/ash/strings/ash_strings_ne.xtb
index 77c9220..4f5f882 100644
--- a/ash/strings/ash_strings_ne.xtb
+++ b/ash/strings/ash_strings_ne.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">सबै डेस्कलाई काम जिम्मा दिइसकिएको छ।</translation>
 <translation id="8555757996376137129">हालको डेस्क हटाउनुहोस्</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> तपाईंलाई <ph name="DEVICE_TYPE" /> अपडेट गर्न सिफारिस गर्छ।</translation>
-<translation id="8563862697512465947">सूचनाका सेटिङहरू</translation>
 <translation id="8569751806372591456">तपाईंले अपनाई हेर्न सक्ने केही सुझाव यस प्रकार छन्</translation>
 <translation id="857201607579416096">मेनु सारेर स्क्रिनको फेदको दायाँ कुनामा लगियो।</translation>
 <translation id="8581946341807941670"><ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> थिच्नुहोस् र कुनै लिंकमा क्लिक गर्नुहोस्</translation>
diff --git a/ash/strings/ash_strings_nl.xtb b/ash/strings/ash_strings_nl.xtb
index a588e884..e4fa16b 100644
--- a/ash/strings/ash_strings_nl.xtb
+++ b/ash/strings/ash_strings_nl.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Al toegewezen aan alle bureaus.</translation>
 <translation id="8555757996376137129">Huidig bureau verwijderen</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> raadt aan dat je je <ph name="DEVICE_TYPE" /> updatet</translation>
-<translation id="8563862697512465947">Meldingsinstellingen</translation>
 <translation id="8569751806372591456">Je kunt de volgende suggesties proberen</translation>
 <translation id="857201607579416096">Menu verplaatst naar rechtsonder in het scherm.</translation>
 <translation id="8581946341807941670">Druk op <ph name="MODIFIER_1" /> + <ph name="MODIFIER_2" /> en klik op een link</translation>
diff --git a/ash/strings/ash_strings_no.xtb b/ash/strings/ash_strings_no.xtb
index da38485..2239132b 100644
--- a/ash/strings/ash_strings_no.xtb
+++ b/ash/strings/ash_strings_no.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Allerede tilordnet til alle skrivebord.</translation>
 <translation id="8555757996376137129">Fjern gjeldende skrivebord</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> anbefaler at du oppdaterer <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Varslingsinnstillinger</translation>
 <translation id="8569751806372591456">Her er noen forslag du kan prøve</translation>
 <translation id="857201607579416096">Menyen ble flyttet til nedre høyre hjørne av skjermen.</translation>
 <translation id="8581946341807941670">Trykk på <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> og klikk på en link</translation>
diff --git a/ash/strings/ash_strings_or.xtb b/ash/strings/ash_strings_or.xtb
index 372b181..b4b16eb6 100644
--- a/ash/strings/ash_strings_or.xtb
+++ b/ash/strings/ash_strings_or.xtb
@@ -1894,7 +1894,6 @@
 <translation id="8553395910833293175">ସମସ୍ତ ଡେସ୍କକୁ ପୂର୍ବରୁ ଆସାଇନ୍ କରାଯାଇଛି।</translation>
 <translation id="8555757996376137129">ବର୍ତ୍ତମାନର ଡେସ୍କ କାଢ଼ି ଦିଅନ୍ତୁ</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> ଆପଣଙ୍କୁ ଆପଣଙ୍କ <ph name="DEVICE_TYPE" />କୁ ଅପଡେଟ କରିବା ପାଇଁ ସୁପାରିଶ କରିଥାଏ</translation>
-<translation id="8563862697512465947">ବିଜ୍ଞପ୍ତି ସେଟିଂସ୍</translation>
 <translation id="8569751806372591456">ବ୍ୟବହାର କରିବାକୁ ଏଠାରେ କିଛି ପରାମର୍ଶ ଅଛି</translation>
 <translation id="857201607579416096">ସ୍କ୍ରିନର ନିମ୍ନ-ଡାହାଣ କୋଣକୁ ମେନୁ ମୁଭ୍ କରାଯାଇଛି।</translation>
 <translation id="8581946341807941670"><ph name="MODIFIER_1" /><ph name="MODIFIER_2" />କୁ ଦବାଇ ଏକ ଲିଙ୍କରେ କ୍ଲିକ କରନ୍ତୁ</translation>
diff --git a/ash/strings/ash_strings_pa.xtb b/ash/strings/ash_strings_pa.xtb
index 70b9a16..4aee8113 100644
--- a/ash/strings/ash_strings_pa.xtb
+++ b/ash/strings/ash_strings_pa.xtb
@@ -358,6 +358,7 @@
 <translation id="2484513351006226581">ਕੀ-ਬੋਰਡ ਖਾਕਾ ਬਦਲਣ ਲਈ <ph name="KEYBOARD_SHORTCUT" /> ਦਬਾਓ।</translation>
 <translation id="2486214324139475545"><ph name="DESK_NAME" /> ਦੀ ਪੂਰਵ-ਝਲਕ। ਕਿਰਿਆਸ਼ੀਲ ਡੈਸਕ।</translation>
 <translation id="2487915095798731898">ਸ਼ਾਮਲ ਹੋਵੋ</translation>
+<translation id="2499445554382787206">ਡੈਸਕ ਪ੍ਰੋਫਾਈਲ ਮੀਨੂ। <ph name="DESK_NAME" /></translation>
 <translation id="2501920221385095727">ਸਟਿਕੀ ਕੁੰਜੀਆਂ</translation>
 <translation id="2504454902900101003">ਆਪਣੇ ਫ਼ੋਨ ਦੀਆਂ ਹਾਲੀਆ ਫ਼ੋਟੋਆਂ, ਮੀਡੀਆ ਅਤੇ ਸੂਚਨਾਵਾਂ ਨੂੰ ਦੇਖਣ ਦਾ ਸੈੱਟਅੱਪ ਕਰਨਾ ਖਾਰਜ ਕਰੋ</translation>
 <translation id="2509468283778169019">CAPS LOCK ਔਨ ਹੈ</translation>
@@ -604,6 +605,7 @@
 <translation id="3509391053705095206">ਤੁਹਾਡਾ ਫ਼ੋਨ ਨਹੀਂ ਲੱਭਿਆ ਜਾ ਸਕਦਾ। ਪੱਕਾ ਕਰੋ ਕਿ ਤੁਹਾਡੇ ਫ਼ੋਨ ਦਾ ਬਲੂਟੁੱਥ ਚਾਲੂ ਹੈ।</translation>
 <translation id="3510164367642747937">ਮਾਊਸ ਕਰਸਰ ਨੂੰ ਉਜਾਗਰ ਕਰੋ</translation>
 <translation id="3513798432020909783"><ph name="MANAGER_EMAIL" /> ਵੱਲੋਂ ਖਾਤੇ ਦਾ ਪ੍ਰਬੰਧਨ ਕੀਤਾ ਜਾਂਦਾ ਹੈ</translation>
+<translation id="3517037892157925473">ਕਾਰਜਾਂ ਨੂੰ ਆਖਰੀ ਵਾਰ ਅੱਪਡੇਟ ਕਰਨ ਦਾ ਸਮਾਂ: <ph name="TIME" />, <ph name="DATE" />.</translation>
 <translation id="352245152354538528">{0,plural, =1{ਡੀਵਾਈਸ ਨੂੰ 1 ਮਿੰਟ ਦੇ ਅੰਦਰ ਅੱਪਡੇਟ ਕਰੋ}one{ਡੀਵਾਈਸ ਨੂੰ # ਮਿੰਟ ਦੇ ਅੰਦਰ ਅੱਪਡੇਟ ਕਰੋ}other{ਡੀਵਾਈਸ ਨੂੰ # ਮਿੰਟਾਂ ਦੇ ਅੰਦਰ ਅੱਪਡੇਟ ਕਰੋ}}</translation>
 <translation id="3522979239100719575">ਉਪਲਬਧ ਪ੍ਰੋਫਾਈਲਾਂ ਨੂੰ ਲੱਭਿਆ ਜਾ ਰਿਹਾ ਹੈ। ਇਸ ਵਿੱਚ ਕੁਝ ਮਿੰਟ ਲੱਗ ਸਕਦੇ ਹਨ।</translation>
 <translation id="3526440770046466733">ਨਵੀਂ ਟੈਬ ਵਿੱਚ ਲਿੰਕ ਖੋਲ੍ਹੋ ਅਤੇ ਮੌਜੂਦਾ ਟੈਬ ਵਿੱਚ ਬਣੇ ਰਹੋ</translation>
@@ -1143,6 +1145,7 @@
 <translation id="5536723544185013515">ਹਾਲੀਆ ਐਪਾਂ, ਸਾਰੀਆਂ ਹਾਲੀਆ ਐਪਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ ਖੱਬੀ ਜਾਂ ਸੱਜੀ ਤੀਰ ਕੁੰਜੀ ਨਾਲ ਨੈਵੀਗੇਟ ਕਰੋ</translation>
 <translation id="553675580533261935">ਸੈਸ਼ਨ ਤੋਂ ਬਾਹਰ ਜਾਇਆ ਜਾ ਰਿਹਾ ਹੈ</translation>
 <translation id="5537725057119320332">ਕਾਸਟ ਕਰੋ</translation>
+<translation id="554017492391497564">ਇਸਦੀ ਮੁਕੰਮਲ ਵਜੋਂ ਨਿਸ਼ਾਨਦੇਹੀ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕੀ।</translation>
 <translation id="5546397813406633847">ਵਰਤੋਂਕਾਰ ਦੇ ਪਾਸਵਰਡ ਨੂੰ ਮੁੜ-ਹਾਸਲ ਕਰੋ</translation>
 <translation id="554893713779400387">ਬੋਲ ਅਨੁਸਾਰ ਲਿਖਤ ਨੂੰ ਟੌਗਲ ਕਰੋ</translation>
 <translation id="5550417424894892620">ਫ਼ਾਈਲਾਂ ਨੂੰ <ph name="HOLDING_SPACE_TITLE" /> ਵਿੱਚ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਉਨ੍ਹਾਂ ਨੂੰ ਡੈਸਕਟਾਪ 'ਤੇ ਛੱਡੋ। ਤੁਸੀਂ ਡੈਸਕਟਾਪ 'ਤੇ ਫ਼ਾਈਲਾਂ ਸ਼ਾਮਲ ਨਹੀਂ ਕਰ ਸਕਦੇ।</translation>
@@ -1337,6 +1340,7 @@
 <translation id="6237231532760393653">1X</translation>
 <translation id="62380141479352646">ਬੈਟਰੀ ਘੱਟ ਹੈ। ਬੈਟਰੀ ਸੇਵਰ ਚਾਲੂ ਹੈ।</translation>
 <translation id="6247728804802644171">ਸੂਚਨਾਵਾਂ ਖੋਲ੍ਹੋ</translation>
+<translation id="6249795363855770621">ਇਸਦੀ ਮੁਕੰਮਲ ਵਜੋਂ ਨਿਸ਼ਾਨਦੇਹੀ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕੀ। ਆਨਲਾਈਨ ਹੋਣ 'ਤੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।</translation>
 <translation id="6254629735336163724">ਲੇਟਵੀਂ ਸਥਿਤੀ ਵਿੱਚ ਲਾਕ ਕੀਤੀ ਗਈ</translation>
 <translation id="6259254695169772643">ਚੁਣਨ ਲਈ ਆਪਣੇ ਸਟਾਈਲਸ ਦੀ ਵਰਤੋਂ ਕਰੋ</translation>
 <translation id="6267036997247669271"><ph name="NAME" />: ਐਕਟੀਵੇਟ ਹੋ ਰਿਹਾ ਹੈ...</translation>
@@ -1497,6 +1501,7 @@
 <translation id="6896758677409633944">ਕਾਪੀ ਕਰੋ</translation>
 <translation id="6912841030378044227">ਪਤਾ ਬਾਰ 'ਤੇ ਫੋਕਸ ਕਰੋ</translation>
 <translation id="6912901278692845878">ਤਤਕਾਲ ਟੂਰ</translation>
+<translation id="6917259695595127329">ਕਾਰਜਾਂ ਨੂੰ ਆਖਰੀ ਵਾਰ ਅੱਪਡੇਟ ਕਰਨ ਦਾ ਸਮਾਂ: <ph name="TIME" />.</translation>
 <translation id="6919251195245069855">ਤੁਹਾਡਾ ਸਮਾਰਟ ਕਾਰਡ ਪਛਾਣਿਆ ਨਹੀਂ ਜਾ ਸਕਿਆ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।</translation>
 <translation id="692135145298539227">ਮਿਟਾਓ</translation>
 <translation id="6929081673585394903">ਕੰਟਰੋਲ ਦਿਖਾਓ</translation>
@@ -1896,7 +1901,6 @@
 <translation id="8553395910833293175">ਪਹਿਲਾਂ ਹੀ ਸਾਰੇ ਡੈਸਕਾਂ ਦੇ ਜ਼ਿੰਮੇ ਲਗਾਇਆ ਗਿਆ।</translation>
 <translation id="8555757996376137129">ਮੌਜੂਦਾ ਡੈਸਕ ਨੂੰ ਹਟਾਓ</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> ਵੱਲੋਂ ਤੁਹਾਨੂੰ ਆਪਣੇ <ph name="DEVICE_TYPE" /> ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਦੀ ਸਿਫ਼ਾਰਸ਼ ਕੀਤੀ ਜਾਂਦੀ ਹੈ</translation>
-<translation id="8563862697512465947">ਸੂਚਨਾ ਸੈਟਿੰਗਾਂ</translation>
 <translation id="8569751806372591456">ਅਜ਼ਮਾਉਣ ਲਈ ਇਹ ਕੁਝ ਸੁਝਾਅ ਹਨ</translation>
 <translation id="857201607579416096">ਮੀਨੂ ਨੂੰ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਲੇ ਸੱਜੇ ਕੋਨੇ ਵਿੱਚ ਲਿਜਾਇਆ ਗਿਆ।</translation>
 <translation id="8581946341807941670"><ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> ਦਬਾ ਕੇ ਲਿੰਕ 'ਤੇ ਕਲਿੱਕ ਕਰੋ</translation>
diff --git a/ash/strings/ash_strings_pl.xtb b/ash/strings/ash_strings_pl.xtb
index 7bafd38..d529d50 100644
--- a/ash/strings/ash_strings_pl.xtb
+++ b/ash/strings/ash_strings_pl.xtb
@@ -1894,7 +1894,6 @@
 <translation id="8553395910833293175">Już przypisano do wszystkich biurek.</translation>
 <translation id="8555757996376137129">Usuń bieżące biurko</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> zaleca aktualizację tego urządzenia <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Ustawienia powiadomień</translation>
 <translation id="8569751806372591456">Oto kilka sugestii, które możesz wypróbować</translation>
 <translation id="857201607579416096">Menu zostało przeniesione w prawy dolny róg ekranu.</translation>
 <translation id="8581946341807941670">Naciśnij <ph name="MODIFIER_1" /> + <ph name="MODIFIER_2" /> i kliknij link</translation>
diff --git a/ash/strings/ash_strings_pt-BR.xtb b/ash/strings/ash_strings_pt-BR.xtb
index 33570f0..9f6db5a 100644
--- a/ash/strings/ash_strings_pt-BR.xtb
+++ b/ash/strings/ash_strings_pt-BR.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Já atribuído a todos os espaços de trabalho.</translation>
 <translation id="8555757996376137129">Remover o espaço de trabalho atual</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> recomenda que você atualize seu <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Configurações de notificação</translation>
 <translation id="8569751806372591456">Confira algumas sugestões</translation>
 <translation id="857201607579416096">O menu foi movido para o canto inferior direito da tela.</translation>
 <translation id="8581946341807941670">Pressione <ph name="MODIFIER_1" /> + <ph name="MODIFIER_2" /> e clique em um link</translation>
diff --git a/ash/strings/ash_strings_pt-PT.xtb b/ash/strings/ash_strings_pt-PT.xtb
index 7460163..dda2d0bd 100644
--- a/ash/strings/ash_strings_pt-PT.xtb
+++ b/ash/strings/ash_strings_pt-PT.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Já atribuído a todos os espaços de trabalho.</translation>
 <translation id="8555757996376137129">Remover espaço de trabalho atual</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> recomenda que atualize o dispositivo <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Definições de notificação</translation>
 <translation id="8569751806372591456">Aqui estão algumas sugestões para experimentar</translation>
 <translation id="857201607579416096">O menu foi movido para o canto inferior direito do ecrã.</translation>
 <translation id="8581946341807941670">Prima <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> e clique num link</translation>
diff --git a/ash/strings/ash_strings_ro.xtb b/ash/strings/ash_strings_ro.xtb
index c2bc364f7..7c85ff78 100644
--- a/ash/strings/ash_strings_ro.xtb
+++ b/ash/strings/ash_strings_ro.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">A fost deja atribuită tuturor desktopurilor.</translation>
 <translation id="8555757996376137129">Elimină desktopul actual</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> recomandă să actualizezi dispozitivul <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Setări de notificare</translation>
 <translation id="8569751806372591456">Iată câteva sugestii de încercat</translation>
 <translation id="857201607579416096">Meniul a fost mutat în colțul din dreapta jos al ecranului.</translation>
 <translation id="8581946341807941670">Apasă pe <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> și dă clic pe un link</translation>
diff --git a/ash/strings/ash_strings_ru.xtb b/ash/strings/ash_strings_ru.xtb
index 4a16c3c..f6c2ef3 100644
--- a/ash/strings/ash_strings_ru.xtb
+++ b/ash/strings/ash_strings_ru.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Уже доступно на всех рабочих столах.</translation>
 <translation id="8555757996376137129">Удалить текущий рабочий стол</translation>
 <translation id="856298576161209842">Согласно рекомендациям <ph name="MANAGER" /> вам нужно обновить устройство <ph name="DEVICE_TYPE" />.</translation>
-<translation id="8563862697512465947">Настройки оповещений</translation>
 <translation id="8569751806372591456">Вот несколько идей:</translation>
 <translation id="857201607579416096">Меню перемещено в правый нижний угол экрана.</translation>
 <translation id="8581946341807941670">Нажмите на ссылку, удерживая <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /></translation>
diff --git a/ash/strings/ash_strings_si.xtb b/ash/strings/ash_strings_si.xtb
index e241bd4..e0a5457 100644
--- a/ash/strings/ash_strings_si.xtb
+++ b/ash/strings/ash_strings_si.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">සියලු මේස වෙත දැනටමත් පවරා ඇත.</translation>
 <translation id="8555757996376137129">වත්මන් මේසය ඉවත් කරන්න</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> ඔබ ඔබගේ <ph name="DEVICE_TYPE" /> යාවත්කාලීන කළ යුතු බව නිර්දේශ කරයි</translation>
-<translation id="8563862697512465947">දැනුම්දීම් සැකසීම්</translation>
 <translation id="8569751806372591456">උත්සාහ කිරීමට යෝජනා කිහිපයක් මෙන්න</translation>
 <translation id="857201607579416096">මෙනුව තිරයේ පහළ දකුණු කොණට ගෙන ගියා.</translation>
 <translation id="8581946341807941670"><ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> ඔබා සබැඳියක් ක්ලික් කරන්න</translation>
diff --git a/ash/strings/ash_strings_sk.xtb b/ash/strings/ash_strings_sk.xtb
index fd5d45a4..b743d29 100644
--- a/ash/strings/ash_strings_sk.xtb
+++ b/ash/strings/ash_strings_sk.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Už bolo pridelené všetkým plochám.</translation>
 <translation id="8555757996376137129">Odstránenie aktuálnej plochy</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> odporúča, aby ste aktualizovali zariadenie <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Nastavenia upozornení</translation>
 <translation id="8569751806372591456">Tu je niekoľko návrhov, ktoré môžete vyskúšať</translation>
 <translation id="857201607579416096">Ponuka bola presunutá do pravého dolného rohu obrazovky.</translation>
 <translation id="8581946341807941670">Stlačte <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> a kliknite na odkaz</translation>
diff --git a/ash/strings/ash_strings_sl.xtb b/ash/strings/ash_strings_sl.xtb
index 730bb67c..3cfc7bf 100644
--- a/ash/strings/ash_strings_sl.xtb
+++ b/ash/strings/ash_strings_sl.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Že dodeljeno vsem namizjem.</translation>
 <translation id="8555757996376137129">Odstranitev trenutnega namizja</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> priporoča, da posodobite napravo <ph name="DEVICE_TYPE" />.</translation>
-<translation id="8563862697512465947">Nastavitve obvestil</translation>
 <translation id="8569751806372591456">Tukaj je nekaj predlogov, ki jih lahko poskusite</translation>
 <translation id="857201607579416096">Meni je bil premaknjen v spodnji desni kot zaslona.</translation>
 <translation id="8581946341807941670">Pritisnite <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> in kliknite povezavo</translation>
diff --git a/ash/strings/ash_strings_sq.xtb b/ash/strings/ash_strings_sq.xtb
index 30ea6fc..93fd04e 100644
--- a/ash/strings/ash_strings_sq.xtb
+++ b/ash/strings/ash_strings_sq.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Është caktuar tashmë te të gjitha tavolinat e punës.</translation>
 <translation id="8555757996376137129">Hiq tavolinën aktuale të punës</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> rekomandon që të përditësosh pajisjen tënde <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Cilësimet e njoftimeve</translation>
 <translation id="8569751806372591456">Këtu janë disa sugjerime për t'i provuar</translation>
 <translation id="857201607579416096">Menyja u zhvendos në këndin poshtë djathtas të ekranit.</translation>
 <translation id="8581946341807941670">Shtyp <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> dhe kliko një lidhje</translation>
diff --git a/ash/strings/ash_strings_sr-Latn.xtb b/ash/strings/ash_strings_sr-Latn.xtb
index d97a2fdf..9f16a1c8 100644
--- a/ash/strings/ash_strings_sr-Latn.xtb
+++ b/ash/strings/ash_strings_sr-Latn.xtb
@@ -358,6 +358,7 @@
 <translation id="2484513351006226581">Pritisnite <ph name="KEYBOARD_SHORTCUT" /> da biste promenili raspored tastature.</translation>
 <translation id="2486214324139475545">Pregled radne površine <ph name="DESK_NAME" />. Aktivna radna površina.</translation>
 <translation id="2487915095798731898">Pridruži me</translation>
+<translation id="2499445554382787206">Meni za profil na radnoj površini. <ph name="DESK_NAME" /></translation>
 <translation id="2501920221385095727">Lepljivi tasteri</translation>
 <translation id="2504454902900101003">Odbacite podešavanje pregleda nedavnih slika, medija i obaveštenja na telefonu</translation>
 <translation id="2509468283778169019">CAPS LOCK je uključen</translation>
@@ -604,6 +605,7 @@
 <translation id="3509391053705095206">Pronalaženje telefona nije uspelo. Proverite da li je Bluetooth na telefonu uključen.</translation>
 <translation id="3510164367642747937">Istakni kursor miša</translation>
 <translation id="3513798432020909783">Nalogom upravlja <ph name="MANAGER_EMAIL" /></translation>
+<translation id="3517037892157925473">Datum i vreme poslednjeg ažuriranja zadataka: <ph name="TIME" />, <ph name="DATE" />.</translation>
 <translation id="352245152354538528">{0,plural, =1{Ažurirajte uređaj u roku od 1 minuta}one{Ažurirajte uređaj u roku od # minuta}few{Ažurirajte uređaj u roku od # minuta}other{Ažurirajte uređaj u roku od # minuta}}</translation>
 <translation id="3522979239100719575">Traže se dostupni profili. To može da potraje nekoliko minuta.</translation>
 <translation id="3526440770046466733">Otvori link na novoj kartici i ostani na aktuelnoj kartici</translation>
@@ -1143,6 +1145,7 @@
 <translation id="5536723544185013515">Nedavne aplikacije, krećite se pomoću tastera sa strelicom nalevo ili nadesno da biste pristupali svim nedavnim aplikacijama</translation>
 <translation id="553675580533261935">Napuštanje sesije</translation>
 <translation id="5537725057119320332">Prebacuj</translation>
+<translation id="554017492391497564">Označavanje stavke kao da je dovršena nije uspelo.</translation>
 <translation id="5546397813406633847">Vrati pristup korisničkom nalogu</translation>
 <translation id="554893713779400387">Uključi/isključi diktiranje</translation>
 <translation id="5550417424894892620">Otpustite fajlove na pozadini da biste ih dodali u <ph name="HOLDING_SPACE_TITLE" />. Ne možete da dodajete fajlove na pozadini.</translation>
@@ -1337,6 +1340,7 @@
 <translation id="6237231532760393653">1X</translation>
 <translation id="62380141479352646">Slaba baterija. Ušteda baterije je uključena.</translation>
 <translation id="6247728804802644171">Otvorite obaveštenja</translation>
+<translation id="6249795363855770621">Označavanje stavke kao da je dovršena nije uspelo. Probajte ponovo kada budete onlajn.</translation>
 <translation id="6254629735336163724">Horizontalni prikaz je zaključan</translation>
 <translation id="6259254695169772643">Izaberite pomoću pisaljke</translation>
 <translation id="6267036997247669271"><ph name="NAME" />: Aktiviranje...</translation>
@@ -1497,6 +1501,7 @@
 <translation id="6896758677409633944">Kopiraj</translation>
 <translation id="6912841030378044227">Fokusiranje na traku za adresu</translation>
 <translation id="6912901278692845878">Kratak obilazak</translation>
+<translation id="6917259695595127329">Vreme poslednjeg ažuriranja zadataka: <ph name="TIME" />.</translation>
 <translation id="6919251195245069855">Nismo uspeli da prepoznamo pametnu karticu. Probajte ponovo.</translation>
 <translation id="692135145298539227">izbriši</translation>
 <translation id="6929081673585394903">Pokaži kontrole</translation>
@@ -1897,7 +1902,6 @@
 <translation id="8553395910833293175">Već je dodeljeno svim radnim površinama.</translation>
 <translation id="8555757996376137129">Ukloni aktuelnu radnu površinu</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> preporučuje da ažurirate <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Podešavanja obaveštenja</translation>
 <translation id="8569751806372591456">Evo par predloga koje možete da isprobate</translation>
 <translation id="857201607579416096">Meni je premešten u donji desni ugao ekrana.</translation>
 <translation id="8581946341807941670">Pritisnite <ph name="MODIFIER_1" /> <ph name="MODIFIER_2" /> i kliknite na link</translation>
diff --git a/ash/strings/ash_strings_sr.xtb b/ash/strings/ash_strings_sr.xtb
index e162d3a..fc429eed 100644
--- a/ash/strings/ash_strings_sr.xtb
+++ b/ash/strings/ash_strings_sr.xtb
@@ -358,6 +358,7 @@
 <translation id="2484513351006226581">Притисните <ph name="KEYBOARD_SHORTCUT" /> да бисте променили распоред тастатуре.</translation>
 <translation id="2486214324139475545">Преглед радне површине <ph name="DESK_NAME" />. Активна радна површина.</translation>
 <translation id="2487915095798731898">Придружи ме</translation>
+<translation id="2499445554382787206">Мени за профил на радној површини. <ph name="DESK_NAME" /></translation>
 <translation id="2501920221385095727">Лепљиви тастери</translation>
 <translation id="2504454902900101003">Одбаците подешавање прегледа недавних слика, медија и обавештења на телефону</translation>
 <translation id="2509468283778169019">CAPS LOCK је укључен</translation>
@@ -604,6 +605,7 @@
 <translation id="3509391053705095206">Проналажење телефона није успело. Проверите да ли је Bluetooth на телефону укључен.</translation>
 <translation id="3510164367642747937">Истакни курсор миша</translation>
 <translation id="3513798432020909783">Налогом управља <ph name="MANAGER_EMAIL" /></translation>
+<translation id="3517037892157925473">Датум и време последњег ажурирања задатака: <ph name="TIME" />, <ph name="DATE" />.</translation>
 <translation id="352245152354538528">{0,plural, =1{Ажурирајте уређај у року од 1 минута}one{Ажурирајте уређај у року од # минута}few{Ажурирајте уређај у року од # минута}other{Ажурирајте уређај у року од # минута}}</translation>
 <translation id="3522979239100719575">Траже се доступни профили. То може да потраје неколико минута.</translation>
 <translation id="3526440770046466733">Отвори линк на новој картици и остани на актуелној картици</translation>
@@ -1143,6 +1145,7 @@
 <translation id="5536723544185013515">Недавне апликације, крећите се помоћу тастера са стрелицом налево или надесно да бисте приступали свим недавним апликацијама</translation>
 <translation id="553675580533261935">Напуштање сесије</translation>
 <translation id="5537725057119320332">Пребацуј</translation>
+<translation id="554017492391497564">Означавање ставке као да је довршена није успело.</translation>
 <translation id="5546397813406633847">Врати приступ корисничком налогу</translation>
 <translation id="554893713779400387">Укључи/искључи диктирање</translation>
 <translation id="5550417424894892620">Отпустите фајлове на позадини да бисте их додали у <ph name="HOLDING_SPACE_TITLE" />. Не можете да додајете фајлове на позадини.</translation>
@@ -1337,6 +1340,7 @@
 <translation id="6237231532760393653">1X</translation>
 <translation id="62380141479352646">Слаба батерија. Уштеда батерије је укључена.</translation>
 <translation id="6247728804802644171">Отворите обавештења</translation>
+<translation id="6249795363855770621">Означавање ставке као да је довршена није успело. Пробајте поново када будете онлајн.</translation>
 <translation id="6254629735336163724">Хоризонтални приказ је закључан</translation>
 <translation id="6259254695169772643">Изаберите помоћу писаљке</translation>
 <translation id="6267036997247669271"><ph name="NAME" />: Активирање...</translation>
@@ -1497,6 +1501,7 @@
 <translation id="6896758677409633944">Копирај</translation>
 <translation id="6912841030378044227">Фокусирање на траку за адресу</translation>
 <translation id="6912901278692845878">Кратак обилазак</translation>
+<translation id="6917259695595127329">Време последњег ажурирања задатака: <ph name="TIME" />.</translation>
 <translation id="6919251195245069855">Нисмо успели да препознамо паметну картицу. Пробајте поново.</translation>
 <translation id="692135145298539227">избриши</translation>
 <translation id="6929081673585394903">Покажи контроле</translation>
@@ -1897,7 +1902,6 @@
 <translation id="8553395910833293175">Већ је додељено свим радним површинама.</translation>
 <translation id="8555757996376137129">Уклони актуелну радну површину</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> препоручује да ажурирате <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Подешавања обавештења</translation>
 <translation id="8569751806372591456">Ево пар предлога које можете да испробате</translation>
 <translation id="857201607579416096">Мени је премештен у доњи десни угао екрана.</translation>
 <translation id="8581946341807941670">Притисните <ph name="MODIFIER_1" /> <ph name="MODIFIER_2" /> и кликните на линк</translation>
diff --git a/ash/strings/ash_strings_sv.xtb b/ash/strings/ash_strings_sv.xtb
index 27bc2740..1d825f4 100644
--- a/ash/strings/ash_strings_sv.xtb
+++ b/ash/strings/ash_strings_sv.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Detta har redan tilldelats alla skrivbord.</translation>
 <translation id="8555757996376137129">Ta bort aktuellt skrivbord</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> rekommenderar att du uppdaterar din <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Aviseringsinställningar</translation>
 <translation id="8569751806372591456">Här är några förslag du kan prova</translation>
 <translation id="857201607579416096">Menyn har flyttats till skärmens nedre högra hörn.</translation>
 <translation id="8581946341807941670">Tryck på <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> och klicka på en länk</translation>
diff --git a/ash/strings/ash_strings_sw.xtb b/ash/strings/ash_strings_sw.xtb
index 9751845..8f58714a 100644
--- a/ash/strings/ash_strings_sw.xtb
+++ b/ash/strings/ash_strings_sw.xtb
@@ -1896,7 +1896,6 @@
 <translation id="8553395910833293175">Tayari limewekwa kwenye maeneokazi yote.</translation>
 <translation id="8555757996376137129">Ondoa eneokazi la sasa</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> inapendekeza usasishe <ph name="DEVICE_TYPE" /> yako</translation>
-<translation id="8563862697512465947">Mipangilio ya Arifa</translation>
 <translation id="8569751806372591456">Yafuatayo ni baadhi ya mapendekezo unayoweza kujaribu</translation>
 <translation id="857201607579416096">Menyu imehamishiwa kwenye kona ya chini kulia mwa skrini.</translation>
 <translation id="8581946341807941670">Bonyeza <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> na ubofye kiungo</translation>
diff --git a/ash/strings/ash_strings_ta.xtb b/ash/strings/ash_strings_ta.xtb
index 56a04b75..3d55fc0 100644
--- a/ash/strings/ash_strings_ta.xtb
+++ b/ash/strings/ash_strings_ta.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">எல்லா டெஸ்க்குகளுக்கும் ஏற்கெனவே ஒதுக்கப்பட்டுள்ளது.</translation>
 <translation id="8555757996376137129">தற்போதைய டெஸ்க்கை அகற்று</translation>
 <translation id="856298576161209842">உங்கள் <ph name="DEVICE_TYPE" /> ஐப் புதுப்பிக்குமாறு <ph name="MANAGER" /> பரிந்துரைக்கிறது</translation>
-<translation id="8563862697512465947">அறிவிப்பு  அமைப்புகள்</translation>
 <translation id="8569751806372591456">இதோ சில பரிந்துரைகள்</translation>
 <translation id="857201607579416096">திரையின் கீழ் வலது மூலைக்கு மெனு நகர்த்தப்பட்டது.</translation>
 <translation id="8581946341807941670"><ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> அழுத்தி, இணைப்பைக் கிளிக் செய்யவும்</translation>
diff --git a/ash/strings/ash_strings_te.xtb b/ash/strings/ash_strings_te.xtb
index 8efa87fd..8142ff8 100644
--- a/ash/strings/ash_strings_te.xtb
+++ b/ash/strings/ash_strings_te.xtb
@@ -1896,7 +1896,6 @@
 <translation id="8553395910833293175">ఇప్పటికే అన్ని డెస్క్‌లకు కేటాయింపు జరిగిపోయింది.</translation>
 <translation id="8555757996376137129">ప్రస్తుత డెస్క్‌ను తీసివేయండి</translation>
 <translation id="856298576161209842">ఈ <ph name="DEVICE_TYPE" />ను అప్‌డేట్ చేయమని <ph name="MANAGER" /> మీకు సిఫార్సు చేస్తోంది</translation>
-<translation id="8563862697512465947">నోటిఫికేషన్ సెట్టింగ్‌లు</translation>
 <translation id="8569751806372591456">ట్రై చేయడానికి ఇక్కడ కొన్ని సూచనలు ఉన్నాయి</translation>
 <translation id="857201607579416096">స్క్రీన్‌లో కింద కుడి వైపు మూలకు మెనూ తరలించబడింది.</translation>
 <translation id="8581946341807941670"><ph name="MODIFIER_1" /><ph name="MODIFIER_2" />ను నొక్కి, లింక్‌ను క్లిక్ చేయండి</translation>
diff --git a/ash/strings/ash_strings_th.xtb b/ash/strings/ash_strings_th.xtb
index 43639ed..12a0fff 100644
--- a/ash/strings/ash_strings_th.xtb
+++ b/ash/strings/ash_strings_th.xtb
@@ -1890,7 +1890,6 @@
 <translation id="8553395910833293175">มอบหมายให้ทุกเดสก์แล้ว</translation>
 <translation id="8555757996376137129">นำเดสก์ปัจจุบันออก</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> แนะนำให้คุณอัปเดต <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">การตั้งค่าการแจ้งเตือน</translation>
 <translation id="8569751806372591456">ลองทำตามคำแนะนำต่อไปนี้</translation>
 <translation id="857201607579416096">เมนูได้ย้ายไปอยู่ที่มุมขวาล่างของหน้าจอ</translation>
 <translation id="8581946341807941670">กด <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> แล้วคลิกลิงก์</translation>
diff --git a/ash/strings/ash_strings_tr.xtb b/ash/strings/ash_strings_tr.xtb
index 7b1df69..146f4f4 100644
--- a/ash/strings/ash_strings_tr.xtb
+++ b/ash/strings/ash_strings_tr.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Zaten tüm masalara atandı.</translation>
 <translation id="8555757996376137129">Geçerli masayı kaldır</translation>
 <translation id="856298576161209842"><ph name="MANAGER" />, <ph name="DEVICE_TYPE" /> cihazınızı güncellemenizi öneriyor</translation>
-<translation id="8563862697512465947">Bildirim Ayarları</translation>
 <translation id="8569751806372591456">Deneyebileceğiniz birkaç öneriyi burada bulabilirsiniz</translation>
 <translation id="857201607579416096">Menü, ekranın sağ alt köşesine taşındı.</translation>
 <translation id="8581946341807941670"><ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> tuşunu basılı tutarken bağlantıyı tıklayın</translation>
diff --git a/ash/strings/ash_strings_uk.xtb b/ash/strings/ash_strings_uk.xtb
index 23e7234..b023997 100644
--- a/ash/strings/ash_strings_uk.xtb
+++ b/ash/strings/ash_strings_uk.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Уже призначено для всіх робочих столів.</translation>
 <translation id="8555757996376137129">Видалити поточний робочий стіл</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> радить оновити пристрій <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">Налаштування сповіщення</translation>
 <translation id="8569751806372591456">Спробуйте ввести наведені нижче запити</translation>
 <translation id="857201607579416096">Меню переміщено в нижній правий кут екрана.</translation>
 <translation id="8581946341807941670">Натисніть <ph name="MODIFIER_1" /><ph name="MODIFIER_2" />, а потім – посилання</translation>
diff --git a/ash/strings/ash_strings_ur.xtb b/ash/strings/ash_strings_ur.xtb
index a7d554c..eaf2e65 100644
--- a/ash/strings/ash_strings_ur.xtb
+++ b/ash/strings/ash_strings_ur.xtb
@@ -1894,7 +1894,6 @@
 <translation id="8553395910833293175">پہلے ہی تمام ڈیسکس کو تفویض کر دیا گیا۔</translation>
 <translation id="8555757996376137129">حالیہ ڈیسک کو ہٹائیں</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> کی تجویز ہے کہ آپ اپنے <ph name="DEVICE_TYPE" /> کو اپ ڈیٹ کریں</translation>
-<translation id="8563862697512465947">اطلاع کی ترتیبات</translation>
 <translation id="8569751806372591456">کوشش کرنے کے لیے یہاں کچھ تجاویز ہیں</translation>
 <translation id="857201607579416096">مینیو کو اسکرین کے نچلے دائیں کونے میں منتقل کر دیا گیا۔</translation>
 <translation id="8581946341807941670"><ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> دبائیں اور کسی لنک پر کلک کریں</translation>
diff --git a/ash/strings/ash_strings_uz.xtb b/ash/strings/ash_strings_uz.xtb
index 2613ac9b..ebaee02 100644
--- a/ash/strings/ash_strings_uz.xtb
+++ b/ash/strings/ash_strings_uz.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Allaqachon barcha ish stollarida mavjud</translation>
 <translation id="8555757996376137129">Joriy ish stolini olib tashlash</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> <ph name="DEVICE_TYPE" /> tizimini eski versiyasiga qaytarishni tavsiya etadi</translation>
-<translation id="8563862697512465947">Bildirishnoma sozlamalari</translation>
 <translation id="8569751806372591456">Quyidagi takliflarni sinang</translation>
 <translation id="857201607579416096">Menyu ekranning quyi oʻng burchagiga surildi.</translation>
 <translation id="8581946341807941670"><ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> bilan havola ustiga bosing</translation>
diff --git a/ash/strings/ash_strings_vi.xtb b/ash/strings/ash_strings_vi.xtb
index 4022bd9..235f518 100644
--- a/ash/strings/ash_strings_vi.xtb
+++ b/ash/strings/ash_strings_vi.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Đã được gán cho tất cả không gian làm việc.</translation>
 <translation id="8555757996376137129">Xoá không gian làm việc hiện tại</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> khuyên bạn nên cập nhật thiết bị <ph name="DEVICE_TYPE" /> của mình</translation>
-<translation id="8563862697512465947">Cài đặt Thông báo</translation>
 <translation id="8569751806372591456">Bạn có thể thử một số gợi ý sau đây</translation>
 <translation id="857201607579416096">Đã di chuyển trình đơn vào góc dưới cùng bên phải màn hình.</translation>
 <translation id="8581946341807941670">Nhấn phím <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> rồi nhấp vào một đường liên kết</translation>
diff --git a/ash/strings/ash_strings_zh-CN.xtb b/ash/strings/ash_strings_zh-CN.xtb
index 5437155..702ab269 100644
--- a/ash/strings/ash_strings_zh-CN.xtb
+++ b/ash/strings/ash_strings_zh-CN.xtb
@@ -1893,7 +1893,6 @@
 <translation id="8553395910833293175">此前就已分配至所有桌面。</translation>
 <translation id="8555757996376137129">移除当前桌面</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> 建议您更新 <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">通知设置</translation>
 <translation id="8569751806372591456">不妨尝试以下搜索建议</translation>
 <translation id="857201607579416096">菜单已移至屏幕的右下角。</translation>
 <translation id="8581946341807941670">在按 <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> 的同时点击链接</translation>
diff --git a/ash/strings/ash_strings_zh-HK.xtb b/ash/strings/ash_strings_zh-HK.xtb
index 498f81a..0e3a671 100644
--- a/ash/strings/ash_strings_zh-HK.xtb
+++ b/ash/strings/ash_strings_zh-HK.xtb
@@ -18,7 +18,7 @@
 <translation id="1056775291175587022">沒有網絡</translation>
 <translation id="1056898198331236512">警告</translation>
 <translation id="1058009965971887428">提供意見</translation>
-<translation id="1059120031266247284">已與你分享</translation>
+<translation id="1059120031266247284">與你分享</translation>
 <translation id="1059194134494239015"><ph name="DISPLAY_NAME" />:<ph name="RESOLUTION" /></translation>
 <translation id="1062407476771304334">取代</translation>
 <translation id="1073899992769346247">請更換電池或充電</translation>
@@ -644,7 +644,7 @@
 <translation id="3621202678540785336">輸入</translation>
 <translation id="3621712662352432595">音效檔案設定</translation>
 <translation id="3626281679859535460">亮度</translation>
-<translation id="3628323833346754646">正面按鈕</translation>
+<translation id="3628323833346754646">前按鈕</translation>
 <translation id="3630697955794050612">關閉</translation>
 <translation id="3631369015426612114">允許顯示來自以下來源的通知</translation>
 <translation id="3633097874324966332">開啟「藍牙設定」以配對裝置</translation>
@@ -1347,7 +1347,7 @@
 <translation id="6309219492973062892">點擊或輕按捷徑列圖示 1-8</translation>
 <translation id="6315170314923504164">語音</translation>
 <translation id="6319058840130157106">在右下角、啟動器、網址列、書籤列、開啟的網站和下載項目之間向後移動</translation>
-<translation id="6319503618073410818">在瀏覽器中查看詳細資料</translation>
+<translation id="6319503618073410818">在瀏覽器中查看詳情</translation>
 <translation id="6324916366299863871">編輯捷徑</translation>
 <translation id="6330012934079202188">顯示緊來自所有桌面嘅視窗,㩒向上箭咀掣就可以顯示來自目前桌面嘅視窗</translation>
 <translation id="6338485349199627913">「<ph name="DISPLAY_NAME" />」是由 <ph name="MANAGER" /> 管理的工作階段</translation>
@@ -1893,7 +1893,6 @@
 <translation id="8553395910833293175">已指派給所有桌面。</translation>
 <translation id="8555757996376137129">移除目前的桌面</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> 建議您更新 <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">通知設定</translation>
 <translation id="8569751806372591456">試試以下幾項建議</translation>
 <translation id="857201607579416096">已經將選單移去螢幕右下角。</translation>
 <translation id="8581946341807941670">按 <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> 鍵,然後按一下連結</translation>
@@ -2023,7 +2022,7 @@
 <translation id="9098969848082897657">將手機設為靜音</translation>
 <translation id="9121941381564890244"><ph name="SNIP" /> 或 <ph name="CTRL" /><ph name="SEPARATOR1" /><ph name="SHIFT" /><ph name="SEPARATOR2" /><ph name="OVERVIEW" /></translation>
 <translation id="9126339866969410112">復原上一個操作</translation>
-<translation id="9129245940793250979">背面按鈕</translation>
+<translation id="9129245940793250979">後按鈕</translation>
 <translation id="9133335900048457298">無法錄影受保護的內容</translation>
 <translation id="9139720510312328767">刪除下一個字母</translation>
 <translation id="9151906066336345901">End 鍵</translation>
diff --git a/ash/strings/ash_strings_zh-TW.xtb b/ash/strings/ash_strings_zh-TW.xtb
index ef09211c..0b7c8cc 100644
--- a/ash/strings/ash_strings_zh-TW.xtb
+++ b/ash/strings/ash_strings_zh-TW.xtb
@@ -1891,7 +1891,6 @@
 <translation id="8553395910833293175">已指派給所有桌面。</translation>
 <translation id="8555757996376137129">移除目前的桌面</translation>
 <translation id="856298576161209842"><ph name="MANAGER" /> 建議你更新 <ph name="DEVICE_TYPE" /></translation>
-<translation id="8563862697512465947">通知設定</translation>
 <translation id="8569751806372591456">試試以下幾項搜尋建議</translation>
 <translation id="857201607579416096">已將選單移至畫面右下角。</translation>
 <translation id="8581946341807941670">按下 <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> 鍵,然後點選連結</translation>
diff --git a/ash/strings/ash_strings_zu.xtb b/ash/strings/ash_strings_zu.xtb
index eec73a1..cbe97513 100644
--- a/ash/strings/ash_strings_zu.xtb
+++ b/ash/strings/ash_strings_zu.xtb
@@ -1895,7 +1895,6 @@
 <translation id="8553395910833293175">Sewusayinde kuwo wonke amatafula.</translation>
 <translation id="8555757996376137129">Susa ideski lamanje</translation>
 <translation id="856298576161209842">I-<ph name="MANAGER" /> incoma ukuba ubuyekeze le <ph name="DEVICE_TYPE" />.</translation>
-<translation id="8563862697512465947">Izilungiselelo Zesaziso</translation>
 <translation id="8569751806372591456">Nakhu ukusikisela okumbalwa ongakuzama</translation>
 <translation id="857201607579416096">Imenyu iyiswe phansi ekhoneni elingakwesokudla sesikrini.</translation>
 <translation id="8581946341807941670">Cindezela okuthi <ph name="MODIFIER_1" /><ph name="MODIFIER_2" /> uphinde uchofoze ilinki</translation>
diff --git a/ash/style/keyboard_shortcut_view.cc b/ash/style/keyboard_shortcut_view.cc
index cbffdd4..9724b4f 100644
--- a/ash/style/keyboard_shortcut_view.cc
+++ b/ash/style/keyboard_shortcut_view.cc
@@ -28,7 +28,7 @@
     auto icon_view = std::make_unique<SearchResultInlineIconView>(
         /*use_modified_styling=*/true, /*is_first_key=*/i == 0);
     icon_view->SetCanProcessEventsWithinSubtree(false);
-    icon_view->GetViewAccessibility().OverrideIsIgnored(true);
+    icon_view->GetViewAccessibility().SetIsIgnored(true);
     icon_view->SetProperty(
         views::kFlexBehaviorKey,
         views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToMinimum,
diff --git a/ash/system/accessibility/accessibility_detailed_view.cc b/ash/system/accessibility/accessibility_detailed_view.cc
index a316c1d..1b50c1c0 100644
--- a/ash/system/accessibility/accessibility_detailed_view.cc
+++ b/ash/system/accessibility/accessibility_detailed_view.cc
@@ -668,7 +668,7 @@
     // Ignore the toggle for accessibility.
     auto& view_accessibility = toggle->GetViewAccessibility();
     view_accessibility.OverrideIsLeaf(true);
-    view_accessibility.OverrideIsIgnored(true);
+    view_accessibility.SetIsIgnored(true);
     item->AddRightView(toggle.release());
   }
   return item;
diff --git a/ash/system/accessibility/dictation_button_tray.cc b/ash/system/accessibility/dictation_button_tray.cc
index a63593a..3208c71 100644
--- a/ash/system/accessibility/dictation_button_tray.cc
+++ b/ash/system/accessibility/dictation_button_tray.cc
@@ -7,6 +7,7 @@
 #include "ash/accessibility/accessibility_controller.h"
 #include "ash/constants/ash_pref_names.h"
 #include "ash/constants/tray_background_view_catalog.h"
+#include "ash/display/window_tree_host_manager.h"
 #include "ash/metrics/user_metrics_recorder.h"
 #include "ash/public/cpp/accessibility_controller_enums.h"
 #include "ash/public/cpp/shelf_config.h"
diff --git a/ash/system/audio/audio_detailed_view.cc b/ash/system/audio/audio_detailed_view.cc
index fc161c0..69445d7d 100644
--- a/ash/system/audio/audio_detailed_view.cc
+++ b/ash/system/audio/audio_detailed_view.cc
@@ -514,7 +514,7 @@
   // Ignore the toggle for accessibility.
   auto& view_accessibility = toggle->GetViewAccessibility();
   view_accessibility.OverrideIsLeaf(true);
-  view_accessibility.OverrideIsIgnored(true);
+  view_accessibility.SetIsIgnored(true);
   noise_cancellation_button_ = toggle.get();
   noise_cancellation_view->AddRightView(toggle.release());
 
diff --git a/ash/system/bluetooth/bluetooth_detailed_view_impl.cc b/ash/system/bluetooth/bluetooth_detailed_view_impl.cc
index aff8256..7ba0bbf 100644
--- a/ash/system/bluetooth/bluetooth_detailed_view_impl.cc
+++ b/ash/system/bluetooth/bluetooth_detailed_view_impl.cc
@@ -219,8 +219,8 @@
   toggle_row_->tri_view()->SetInsets(kToggleRowTriViewInsets);
 
   // ChromeVox users will just use the `toggle_button_` to toggle.
-  toggle_icon_->GetViewAccessibility().OverrideIsIgnored(true);
-  toggle_row_->text_label()->GetViewAccessibility().OverrideIsIgnored(true);
+  toggle_icon_->GetViewAccessibility().SetIsIgnored(true);
+  toggle_row_->text_label()->GetViewAccessibility().SetIsIgnored(true);
 }
 
 void BluetoothDetailedViewImpl::CreateMainContainer() {
diff --git a/ash/system/brightness/display_detailed_view.cc b/ash/system/brightness/display_detailed_view.cc
index 687ebe4..8a32dce3c 100644
--- a/ash/system/brightness/display_detailed_view.cc
+++ b/ash/system/brightness/display_detailed_view.cc
@@ -17,6 +17,7 @@
 #include "ash/system/night_light/night_light_feature_pod_controller.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/system/tray/detailed_view_delegate.h"
+#include "ash/system/tray/tray_constants.h"
 #include "ash/system/tray/tray_popup_utils.h"
 #include "ash/system/unified/feature_tile.h"
 #include "ash/system/unified/unified_system_tray.h"
@@ -26,6 +27,8 @@
 #include "ui/views/border.h"
 #include "ui/views/controls/scroll_view.h"
 #include "ui/views/layout/flex_layout.h"
+#include "ui/views/layout/flex_layout_types.h"
+#include "ui/views/layout/flex_layout_view.h"
 #include "ui/views/view.h"
 #include "ui/views/view_class_properties.h"
 
@@ -34,9 +37,9 @@
 namespace {
 
 constexpr auto kScrollViewMargin = gfx::Insets::TLBR(0, 12, 16, 12);
-constexpr auto kTileMargin = gfx::Insets::TLBR(4, 4, 12, 4);
-constexpr auto kSliderPadding = gfx::Insets::TLBR(0, 0, 4, 0);
 constexpr auto kSliderBorder = gfx::Insets(4);
+constexpr auto kSliderPadding = gfx::Insets::TLBR(0, 0, 4, 0);
+constexpr auto kTileContainerMargins = gfx::Insets::TLBR(4, 4, 12, 4);
 
 }  // namespace
 
@@ -56,21 +59,30 @@
   auto dark_mode_controller = std::make_unique<DarkModeFeaturePodController>(
       unified_system_tray_controller_);
 
-  auto tile_container = std::make_unique<views::View>();
-  // Sets the ID for testing.
-  tile_container->SetID(VIEW_ID_QS_DISPLAY_TILE_CONTAINER);
+  auto tile_container =
+      views::Builder<views::FlexLayoutView>()
+          .SetID(VIEW_ID_QS_DISPLAY_TILE_CONTAINER)
+          .SetPreferredSize(
+              gfx::Size(GetPreferredSize().width(),
+                        kFeatureTileHeight + kTileContainerMargins.height()))
+          .CustomConfigure(base::BindOnce([](views::FlexLayoutView* layout) {
+            layout->SetDefault(views::kMarginsKey, kTileContainerMargins);
+          }))
+          .Build();
+
   tile_container->AddChildView(night_light_controller->CreateTile());
   tile_container->AddChildView(dark_mode_controller->CreateTile());
 
-  // Transfers the ownership so the controllers won't die while the page is
-  // open.
+  // Set `PreferredSize` to (1,1) so the `FlexLayout` allocates the same width
+  // for the child tiles based on their equal weights.
+  for (auto tile : tile_container->children()) {
+    tile->SetPreferredSize(gfx::Size(1, 1));
+  }
+
+  // Transfer ownership so the controllers won't die while the page is open.
   feature_tile_controllers_.push_back(std::move(night_light_controller));
   feature_tile_controllers_.push_back(std::move(dark_mode_controller));
 
-  auto* tile_layout =
-      tile_container->SetLayoutManager(std::make_unique<views::FlexLayout>());
-  tile_layout->SetDefault(views::kMarginsKey, kTileMargin);
-
   scroll_content()->AddChildView(std::move(tile_container));
 
   brightness_slider_controller_ =
diff --git a/ash/system/holding_space/holding_space_item_chip_view.cc b/ash/system/holding_space/holding_space_item_chip_view.cc
index 7433dc8..5d0adeb4 100644
--- a/ash/system/holding_space/holding_space_item_chip_view.cc
+++ b/ash/system/holding_space/holding_space_item_chip_view.cc
@@ -141,7 +141,7 @@
   }
 
   void SetViewAccessibilityIsIgnored(bool is_ignored) {
-    GetViewAccessibility().OverrideIsIgnored(is_ignored);
+    GetViewAccessibility().SetIsIgnored(is_ignored);
   }
 
  private:
diff --git a/ash/system/network/network_feature_tile_pixeltest.cc b/ash/system/network/network_feature_tile_pixeltest.cc
index b2f09f0..5d4ff5e 100644
--- a/ash/system/network/network_feature_tile_pixeltest.cc
+++ b/ash/system/network/network_feature_tile_pixeltest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "ash/system/network/network_feature_pod_controller.h"
+#include "ash/system/tray/tray_constants.h"
 #include "ash/system/unified/unified_system_tray.h"
 #include "ash/system/unified/unified_system_tray_bubble.h"
 #include "ash/test/ash_test_base.h"
@@ -12,7 +13,9 @@
 #include "chromeos/ash/services/network_config/public/cpp/cros_network_config_test_helper.h"
 #include "chromeos/constants/chromeos_features.h"
 #include "ui/chromeos/styles/cros_tokens_color_mappings.h"
+#include "ui/views/layout/flex_layout_types.h"
 #include "ui/views/view.h"
+#include "ui/views/view_class_properties.h"
 #include "ui/views/widget/widget.h"
 
 namespace ash {
@@ -36,6 +39,19 @@
 constexpr char kServicePatternWiFi[] = R"({
     "GUID": "%s", "Type": "wifi", "State": "online",
     "Strength": 100, "SecurityClass": "%s"})";
+
+// Configures a `Feature Tile` base to follow Quick Settings sizing standards.
+void ConfigureQSFeatureTile(FeatureTile* tile) {
+  // Quick Settings Feature Tiles set a fixed size for their feature tiles.
+  tile->SetPreferredSize(
+      gfx::Size(kPrimaryFeatureTileWidth, kFeatureTileHeight));
+  tile->SetProperty(
+      views::kFlexBehaviorKey,
+      views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToZero,
+                               views::MaximumFlexSizeRule::kPreferred,
+                               /*adjust_height_for_width=*/false));
+}
+
 }  // namespace
 
 // Pixel test for the quick settings network feature tile view.
@@ -69,6 +85,7 @@
 
     feature_tile_ =
         widget_->GetContentsView()->AddChildView(std::move(feature_tile));
+    ConfigureQSFeatureTile(feature_tile_);
 
     // Add the non-default cellular and ethernet devices to Shill.
     network_state_helper()->manager_test()->AddTechnology(shill::kTypeCellular,
diff --git a/ash/system/network/network_list_network_header_view.cc b/ash/system/network/network_list_network_header_view.cc
index 497cb3d..6155e0f 100644
--- a/ash/system/network/network_list_network_header_view.cc
+++ b/ash/system/network/network_list_network_header_view.cc
@@ -56,8 +56,8 @@
   entry_row()->SetExpandable(true);
   entry_row()->AddRightView(toggle.release());
   // ChromeVox users will use the `toggle_` to toggle the feature.
-  entry_row()->left_view()->GetViewAccessibility().OverrideIsIgnored(true);
-  entry_row()->text_label()->GetViewAccessibility().OverrideIsIgnored(true);
+  entry_row()->left_view()->GetViewAccessibility().SetIsIgnored(true);
+  entry_row()->text_label()->GetViewAccessibility().SetIsIgnored(true);
 }
 
 NetworkListNetworkHeaderView::~NetworkListNetworkHeaderView() = default;
diff --git a/ash/system/tray/tray_background_view_unittest.cc b/ash/system/tray/tray_background_view_unittest.cc
index 7c266bce..2a6a6da 100644
--- a/ash/system/tray/tray_background_view_unittest.cc
+++ b/ash/system/tray/tray_background_view_unittest.cc
@@ -16,6 +16,7 @@
 #include "ash/system/tray/tray_bubble_wrapper.h"
 #include "ash/system/tray/tray_utils.h"
 #include "ash/test/ash_test_base.h"
+#include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "base/memory/raw_ptr.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/task_environment.h"
@@ -23,6 +24,8 @@
 #include "ui/compositor/layer_animator.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
 #include "ui/compositor/test/layer_animation_stopped_waiter.h"
+#include "ui/display/manager/display_manager.h"
+#include "ui/display/manager/managed_display_info.h"
 
 namespace ash {
 
diff --git a/ash/system/tray/tray_constants.h b/ash/system/tray/tray_constants.h
index 8266606..3a2c98d 100644
--- a/ash/system/tray/tray_constants.h
+++ b/ash/system/tray/tray_constants.h
@@ -213,6 +213,8 @@
 inline constexpr int kFeatureTileMaxRows = 4;
 inline constexpr int kFeatureTileMaxRowsWhenMediaViewIsShowing = 3;
 inline constexpr int kFeatureTileMinRows = 1;
+inline constexpr int kPrimaryFeatureTileWidth = 180;
+inline constexpr int kCompactFeatureTileWidth = 86;
 inline constexpr int kFeatureTileHeight = 64;
 
 // Constants used in system tray page transition animations.
diff --git a/ash/system/tray/tray_detailed_view.cc b/ash/system/tray/tray_detailed_view.cc
index 38f000af..93e70639 100644
--- a/ash/system/tray/tray_detailed_view.cc
+++ b/ash/system/tray/tray_detailed_view.cc
@@ -46,6 +46,7 @@
 #include "ui/views/controls/scroll_view.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/box_layout_view.h"
+#include "ui/views/layout/flex_layout_view.h"
 #include "ui/views/view_class_properties.h"
 #include "ui/views/view_targeter.h"
 #include "ui/views/view_targeter_delegate.h"
@@ -165,11 +166,12 @@
 
 void TrayDetailedView::CreateScrollableList() {
   DCHECK(!scroller_);
-  auto scroll_content = std::make_unique<views::BoxLayoutView>();
-  scroll_content->SetOrientation(views::BoxLayout::Orientation::kVertical);
   scroller_ = AddChildView(std::make_unique<views::ScrollView>());
   scroller_->SetDrawOverflowIndicator(false);
-  scroll_content_ = scroller_->SetContents(std::move(scroll_content));
+  scroll_content_ = scroller_->SetContents(
+      views::Builder<views::FlexLayoutView>()
+          .SetOrientation(views::LayoutOrientation::kVertical)
+          .Build());
 
   auto vertical_scroll = std::make_unique<RoundedScrollBar>(
       views::ScrollBar::Orientation::kVertical);
diff --git a/ash/system/unified/feature_tile.cc b/ash/system/unified/feature_tile.cc
index 95d95c2..f48635ef1 100644
--- a/ash/system/unified/feature_tile.cc
+++ b/ash/system/unified/feature_tile.cc
@@ -36,7 +36,6 @@
 #include "ui/views/controls/highlight_path_generator.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
-#include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/flex_layout.h"
 #include "ui/views/layout/flex_layout_view.h"
 #include "ui/views/layout/layout_types.h"
@@ -56,7 +55,6 @@
 constexpr float kFocusRingPadding = 3.0f;
 
 // Primary tile constants
-constexpr gfx::Size kDefaultSize(180, kFeatureTileHeight);
 constexpr gfx::Size kIconButtonSize(36, 52);
 constexpr int kIconButtonCornerRadius = 12;
 constexpr gfx::Insets kIconButtonMargins = gfx::Insets::VH(6, 6);
@@ -68,7 +66,6 @@
 // Compact tile constants
 constexpr int kCompactWidth = 86;
 constexpr int kCompactTitleLineHeight = 14;
-constexpr gfx::Size kCompactSize(kCompactWidth, kFeatureTileHeight);
 constexpr gfx::Size kCompactIconButtonSize(kIconSize, kIconSize);
 constexpr gfx::Insets kCompactIconButtonMargins =
     gfx::Insets::TLBR(6, 22, 4, 22);
@@ -205,10 +202,17 @@
 void FeatureTile::CreateChildViews() {
   const bool is_compact = type_ == TileType::kCompact;
 
-  auto* layout_manager = SetLayoutManager(std::make_unique<views::BoxLayout>());
-  layout_manager->SetOrientation(
-      is_compact ? views::BoxLayout::Orientation::kVertical
-                 : views::BoxLayout::Orientation::kHorizontal);
+  SetLayoutManager(std::make_unique<views::FlexLayout>())
+      ->SetOrientation(is_compact ? views::LayoutOrientation::kVertical
+                                  : views::LayoutOrientation::kHorizontal)
+      .SetMainAxisAlignment(views::LayoutAlignment::kCenter);
+  // Set `MaximumFlexSizeRule` to `kUnbounded` so the view takes up all of the
+  // available space in its parent container.
+  SetProperty(views::kFlexBehaviorKey,
+              views::FlexSpecification(views::FlexSpecification(
+                  views::MinimumFlexSizeRule::kScaleToZero,
+                  views::MaximumFlexSizeRule::kUnbounded,
+                  /*adjust_height_for_width=*/true)));
 
   ink_drop_container_ =
       AddChildView(std::make_unique<views::InkDropContainerView>());
@@ -216,8 +220,6 @@
   auto* focus_ring = views::FocusRing::Get(this);
   focus_ring->SetColorId(cros_tokens::kCrosSysFocusRing);
 
-  SetPreferredSize(is_compact ? kCompactSize : kDefaultSize);
-
   icon_button_ = AddChildView(std::make_unique<views::ImageButton>());
   icon_button_->SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
   icon_button_->SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
@@ -230,11 +232,23 @@
   icon_button_->SetEnabled(false);
   icon_button_->SetCanProcessEventsWithinSubtree(false);
 
-  title_container_ = AddChildView(std::make_unique<FlexLayoutView>());
-  title_container_->SetCanProcessEventsWithinSubtree(false);
-  title_container_->SetOrientation(views::LayoutOrientation::kVertical);
-  title_container_->SetMainAxisAlignment(views::LayoutAlignment::kCenter);
-  title_container_->SetCrossAxisAlignment(views::LayoutAlignment::kStretch);
+  title_container_ =
+      AddChildView(views::Builder<FlexLayoutView>()
+                       .SetCanProcessEventsWithinSubtree(false)
+                       .SetOrientation(views::LayoutOrientation::kVertical)
+                       .SetMainAxisAlignment(views::LayoutAlignment::kCenter)
+                       .SetCrossAxisAlignment(views::LayoutAlignment::kStretch)
+                       .Build());
+  // Set `MaximumFlexSizeRule` to `kUnbounded` so that `title_container_` takes
+  // up all of the available space in the middle of the primary tile.
+  if (!is_compact) {
+    title_container_->SetProperty(
+        views::kFlexBehaviorKey,
+        views::FlexSpecification(
+            views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToZero,
+                                     views::MaximumFlexSizeRule::kUnbounded,
+                                     /*adjust_height_for_width=*/true)));
+  }
 
   label_ = title_container_->AddChildView(std::make_unique<views::Label>());
   label_->SetAutoColorReadabilityEnabled(false);
@@ -263,7 +277,6 @@
     sub_label_->SetVisible(false);
   } else {
     // `title_container_` will take all the remaining space of the tile.
-    layout_manager->SetFlexForView(title_container_, 1);
     title_container_->SetProperty(views::kMarginsKey,
                                   kTitleContainerWithoutDiveInButtonMargins);
     label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
@@ -300,7 +313,8 @@
 }
 
 void FeatureTile::CreateDecorativeDrillInArrow() {
-  CHECK_EQ(type_, TileType::kPrimary);
+  CHECK_EQ(type_, TileType::kPrimary)
+      << "Drill-in arrows are just used in Primary tiles";
 
   title_container_->SetProperty(views::kMarginsKey,
                                 kTitleContainerWithDiveInButtonMargins);
@@ -465,6 +479,9 @@
   }
 
   label_->SetText(label);
+  if (GetTooltipText().empty()) {
+    SetTooltipText(label);
+  }
 }
 
 int FeatureTile::GetSubLabelMaxWidth() const {
@@ -557,6 +574,12 @@
   ink_drop_container_->RemoveLayerFromRegions(layer);
 }
 
+void FeatureTile::OnBoundsChanged(const gfx::Rect& previous_bounds) {
+  // Manual updating of the focus ring is necessary due to b/326983304, where it
+  // fails to update when the bounds of a view with a `FlexLayout` change.
+  views::FocusRing::Get(this)->InvalidateLayout();
+}
+
 ui::ColorId FeatureTile::GetIconColorId() const {
   if (!GetEnabled()) {
     return cros_tokens::kCrosSysDisabled;
diff --git a/ash/system/unified/feature_tile.h b/ash/system/unified/feature_tile.h
index 7becbc8..9515fb1 100644
--- a/ash/system/unified/feature_tile.h
+++ b/ash/system/unified/feature_tile.h
@@ -175,6 +175,7 @@
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
   void AddLayerToRegion(ui::Layer* layer, views::LayerRegion region) override;
   void RemoveLayerFromRegions(ui::Layer* layer) override;
+  void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
 
   base::WeakPtr<FeatureTile> GetWeakPtr() {
     return weak_ptr_factory_.GetWeakPtr();
diff --git a/ash/system/unified/feature_tile_pixeltest.cc b/ash/system/unified/feature_tile_pixeltest.cc
index 9b49e1d..e49c397 100644
--- a/ash/system/unified/feature_tile_pixeltest.cc
+++ b/ash/system/unified/feature_tile_pixeltest.cc
@@ -5,6 +5,7 @@
 #include <memory>
 
 #include "ash/constants/ash_features.h"
+#include "ash/system/tray/tray_constants.h"
 #include "ash/system/unified/feature_tile.h"
 #include "ash/system/video_conference/fake_video_conference_tray_controller.h"
 #include "ash/test/ash_test_base.h"
@@ -28,8 +29,36 @@
 #include "ui/views/widget/widget.h"
 
 namespace ash {
+
 namespace {
 
+// Quick Settings `FeatureTile` size constants.
+constexpr gfx::Size kQSPrimaryTileSize =
+    gfx::Size(kPrimaryFeatureTileWidth, kFeatureTileHeight);
+constexpr gfx::Size kQSCompactTileSize =
+    gfx::Size(kCompactFeatureTileWidth, kFeatureTileHeight);
+
+// Creates a `Feature Tile` base that follows Quick Settings sizing standards.
+FeatureTile* CreateQSFeatureTileBase(views::Widget* widget,
+                                     bool is_compact = false) {
+  auto tile = std::make_unique<FeatureTile>(
+      views::Button::PressedCallback(), /*is_togglable=*/true,
+      is_compact ? FeatureTile::TileType::kCompact
+                 : FeatureTile::TileType::kPrimary);
+
+  // Quick Settings Feature Tiles set a fixed size for their feature tiles.
+  tile->SetPreferredSize(is_compact ? kQSCompactTileSize : kQSPrimaryTileSize);
+  tile->SetProperty(
+      views::kFlexBehaviorKey,
+      views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToZero,
+                               views::MaximumFlexSizeRule::kPreferred,
+                               /*adjust_height_for_width=*/false));
+
+  return widget->GetContentsView()->AddChildView(std::move(tile));
+}
+
+}  // namespace
+
 // Pixel tests for the quick settings feature tile view.
 class FeatureTilePixelTest : public AshTestBase {
  public:
@@ -76,10 +105,7 @@
 };
 
 TEST_F(FeatureTilePixelTest, PrimaryTile) {
-  auto* tile =
-      widget_->GetContentsView()->AddChildView(std::make_unique<FeatureTile>(
-          views::Button::PressedCallback(), /*is_togglable=*/true,
-          FeatureTile::TileType::kPrimary));
+  auto* tile = CreateQSFeatureTileBase(widget_.get());
   tile->SetVectorIcon(vector_icons::kDogfoodIcon);
   tile->SetLabel(u"Label");
   tile->SetSubLabel(u"Sub-label");
@@ -110,10 +136,7 @@
 }
 
 TEST_F(FeatureTilePixelTest, PrimaryTileWithoutDiveInButton) {
-  auto* tile =
-      widget_->GetContentsView()->AddChildView(std::make_unique<FeatureTile>(
-          views::Button::PressedCallback(), /*is_togglable=*/true,
-          FeatureTile::TileType::kPrimary));
+  auto* tile = CreateQSFeatureTileBase(widget_.get());
   tile->SetVectorIcon(vector_icons::kDogfoodIcon);
   tile->SetLabel(u"Label");
   tile->SetSubLabel(u"Sub-label");
@@ -148,10 +171,7 @@
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(base::i18n::IsRTL());
 
-  auto* tile =
-      widget_->GetContentsView()->AddChildView(std::make_unique<FeatureTile>(
-          views::Button::PressedCallback(), /*is_togglable=*/true,
-          FeatureTile::TileType::kPrimary));
+  auto* tile = CreateQSFeatureTileBase(widget_.get());
   tile->SetVectorIcon(vector_icons::kDogfoodIcon);
   tile->SetLabel(u"Label");
   tile->SetSubLabel(u"Sub-label");
@@ -166,10 +186,7 @@
 }
 
 TEST_F(FeatureTilePixelTest, CompactTile) {
-  auto* tile =
-      widget_->GetContentsView()->AddChildView(std::make_unique<FeatureTile>(
-          views::Button::PressedCallback(), /*is_togglable=*/true,
-          FeatureTile::TileType::kCompact));
+  auto* tile = CreateQSFeatureTileBase(widget_.get(), /*is_compact=*/true);
   tile->SetVectorIcon(vector_icons::kDogfoodIcon);
   tile->SetLabel(u"Multi-line label");
   // Needed for accessibility paint checks.
@@ -347,5 +364,4 @@
       /*revision_number=*/0, widget_.get()));
 }
 
-}  // namespace
 }  // namespace ash
diff --git a/ash/system/unified/feature_tiles_container_view.cc b/ash/system/unified/feature_tiles_container_view.cc
index bc3659dc..fb44164 100644
--- a/ash/system/unified/feature_tiles_container_view.cc
+++ b/ash/system/unified/feature_tiles_container_view.cc
@@ -38,8 +38,15 @@
       return kPrimaryTileWeight;
     case FeatureTile::TileType::kCompact:
       return kCompactTileWeight;
-    default:
-      NOTREACHED();
+  }
+}
+
+int GetTileWidth(FeatureTile::TileType type) {
+  switch (type) {
+    case FeatureTile::TileType::kPrimary:
+      return kPrimaryFeatureTileWidth;
+    case FeatureTile::TileType::kCompact:
+      return kCompactFeatureTileWidth;
   }
 }
 
@@ -141,6 +148,13 @@
     // Invisible tiles don't take any weight.
     if (tile->GetVisible()) {
       row_weight += GetTileWeight(tile->tile_type());
+      tile->SetPreferredSize(
+          gfx::Size(GetTileWidth(tile->tile_type()), kFeatureTileHeight));
+      tile->SetProperty(
+          views::kFlexBehaviorKey,
+          views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToZero,
+                                   views::MaximumFlexSizeRule::kPreferred,
+                                   /*adjust_height_for_width=*/true));
     }
     DCHECK_LE(row_weight, kMaxRowWeight);
     rows_.back()->AddChildView(std::move(tile));
diff --git a/ash/system/unified/unified_system_tray.cc b/ash/system/unified/unified_system_tray.cc
index 3203325..624faa8 100644
--- a/ash/system/unified/unified_system_tray.cc
+++ b/ash/system/unified/unified_system_tray.cc
@@ -550,7 +550,7 @@
 }
 
 void UnifiedSystemTray::UpdateTrayItemColor(bool is_active) {
-  for (auto* tray_item : tray_items_) {
+  for (TrayItemView* tray_item : tray_items_) {
     tray_item->UpdateLabelOrImageViewColor(is_active);
   }
 }
diff --git a/ash/system/unified/unified_system_tray.h b/ash/system/unified/unified_system_tray.h
index 83485304..1f211c06 100644
--- a/ash/system/unified/unified_system_tray.h
+++ b/ash/system/unified/unified_system_tray.h
@@ -256,7 +256,7 @@
   raw_ptr<ChannelIndicatorView> channel_indicator_view_ = nullptr;
 
   // Contains all tray items views added to tray_container().
-  std::list<TrayItemView*> tray_items_;
+  std::list<raw_ptr<TrayItemView, CtnExperimental>> tray_items_;
 
   bool first_interaction_recorded_ = false;
 
diff --git a/ash/utility/occlusion_tracker_pauser.h b/ash/utility/occlusion_tracker_pauser.h
index 054015a..9aeb888 100644
--- a/ash/utility/occlusion_tracker_pauser.h
+++ b/ash/utility/occlusion_tracker_pauser.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "ash/ash_export.h"
+#include "base/memory/raw_ptr.h"
 #include "base/scoped_multi_source_observation.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
@@ -49,7 +50,8 @@
 
   // Keeps track of compositors that are animating. We can unpause when this is
   // empty.
-  base::flat_set<ui::Compositor*> animating_compositors_;
+  base::flat_set<raw_ptr<ui::Compositor, CtnExperimental>>
+      animating_compositors_;
 
   std::unique_ptr<aura::WindowOcclusionTracker::ScopedPause> scoped_pause_;
 };
diff --git a/ash/webui/camera_app_ui/resources.h b/ash/webui/camera_app_ui/resources.h
index 3a72b92..61edb3c 100644
--- a/ash/webui/camera_app_ui/resources.h
+++ b/ash/webui/camera_app_ui/resources.h
@@ -60,12 +60,6 @@
     {"expert_enable_full_sized_video_snapshot",
      IDS_EXPERT_ENABLE_FULL_SIZED_VIDEO_SNAPSHOT},
     {"expert_enable_ptz_for_builtin", IDS_EXPERT_ENABLE_PTZ_FOR_BUILTIN},
-    {"expert_multistream_recording", IDS_EXPERT_MULTISTREAM_RECORDING},
-    {"expert_multistream_recording_chrome",
-     IDS_EXPERT_MULTISTREAM_RECORDING_CHROME},
-    {"expert_multistream_recording_disabled",
-     IDS_EXPERT_MULTISTREAM_RECORDING_DISABLED},
-    {"expert_multistream_recording_hal", IDS_EXPERT_MULTISTREAM_RECORDING_HAL},
     {"expert_mode_button", IDS_EXPERT_MODE_BUTTON},
     {"expert_preview_metadata", IDS_EXPERT_PREVIEW_METADATA},
     {"expert_print_performance_logs", IDS_EXPERT_PRINT_PERFORMANCE_LOGS},
diff --git a/ash/webui/camera_app_ui/resources/js/device/camera_operation.ts b/ash/webui/camera_app_ui/resources/js/device/camera_operation.ts
index 309145e..b75ee697 100644
--- a/ash/webui/camera_app_ui/resources/js/device/camera_operation.ts
+++ b/ash/webui/camera_app_ui/resources/js/device/camera_operation.ts
@@ -28,10 +28,10 @@
   FakeCameraCaptureCandidate,
 } from './capture_candidate.js';
 import {CaptureCandidatePreferrer} from './capture_candidate_preferrer.js';
+import {DeviceMonitor} from './device_monitor.js';
 import {Modes, Video} from './mode/index.js';
 import {Preview} from './preview.js';
 import {StreamConstraints} from './stream_constraints.js';
-import {StreamManager} from './stream_manager.js';
 import {
   CameraConfig,
   CameraConfigCandidate,
@@ -409,6 +409,8 @@
 
   private readonly togglePausedEventQueue = new AsyncJobQueue('drop');
 
+  private readonly deviceMonitor = new DeviceMonitor();
+
   constructor(
       private readonly listener: EventListener,
       preview: Preview,
@@ -423,7 +425,7 @@
         defaultFacing,
     );
     this.capturer = new Capturer(this.modes);
-    StreamManager.getInstance().addRealDeviceChangeListener((devices) => {
+    this.deviceMonitor.addDeviceChangeListener((devices) => {
       const info = new CameraInfo(devices);
       if (this.ongoingOperationType !== null) {
         this.pendingUpdateInfo = info;
@@ -435,7 +437,7 @@
 
   async initialize(cameraViewUI: CameraViewUI): Promise<void> {
     this.modes.initialize(cameraViewUI);
-    await StreamManager.getInstance().deviceUpdate();
+    await this.deviceMonitor.deviceUpdate();
     await this.firstInfoUpdate.wait();
   }
 
diff --git a/ash/webui/camera_app_ui/resources/js/device/capture_candidate.ts b/ash/webui/camera_app_ui/resources/js/device/capture_candidate.ts
index 8d0b9ae8..93082e0 100644
--- a/ash/webui/camera_app_ui/resources/js/device/capture_candidate.ts
+++ b/ash/webui/camera_app_ui/resources/js/device/capture_candidate.ts
@@ -129,8 +129,7 @@
   }
 
   getStreamConstraintsCandidates(): StreamConstraints[] {
-    // For non-multistream recording, preview stream is used directly
-    // to do video recording.
+    // Preview stream is used directly to do video recording.
     const {width, height} = this.resolution;
     const buildConstraint = (frameRate: MediaTrackConstraints['frameRate']) =>
         ({
@@ -159,45 +158,6 @@
   }
 }
 
-export class MultiStreamVideoCaptureCandidate extends VideoCaptureCandidate {
-  constructor(
-      deviceId: string, resolution: Resolution,
-      previewResolutions: Resolution[], constFps: number|null,
-      hasAudio: boolean) {
-    super(deviceId, resolution, previewResolutions, constFps, hasAudio);
-  }
-
-  override getStreamConstraintsCandidates(): StreamConstraints[] {
-    const frameRate =
-        this.constFps === null ? {min: 20, ideal: 30} : {exact: this.constFps};
-    const buildConstraint =
-        (frameRate: MediaTrackConstraints['frameRate'],
-         {width, height}: Resolution) => ({
-          deviceId: this.deviceId,
-          audio: this.hasAudio,
-          video: {
-            frameRate,
-            width,
-            height,
-          },
-        });
-    const streamConstraints = [];
-    for (const previewResolution of this.previewResolutions) {
-      streamConstraints.push(buildConstraint(frameRate, previewResolution));
-    }
-
-    // If another web app is opened and requests a low fps streaming, CCA will
-    // get an OverconstrainedError. In this case, the constraint is relaxed but
-    // the error message is kept in the log.
-    if (this.constFps === null) {
-      for (const previewResolution of this.previewResolutions) {
-        streamConstraints.push(buildConstraint({ideal: 30}, previewResolution));
-      }
-    }
-    return streamConstraints;
-  }
-}
-
 export class FakeCameraCaptureCandidate implements CaptureCandidate {
   readonly resolution = null;
 
diff --git a/ash/webui/camera_app_ui/resources/js/device/capture_candidate_preferrer.ts b/ash/webui/camera_app_ui/resources/js/device/capture_candidate_preferrer.ts
index d3e0cc7..78e1a45 100644
--- a/ash/webui/camera_app_ui/resources/js/device/capture_candidate_preferrer.ts
+++ b/ash/webui/camera_app_ui/resources/js/device/capture_candidate_preferrer.ts
@@ -22,7 +22,6 @@
 } from './camera3_device_info.js';
 import {
   CaptureCandidate,
-  MultiStreamVideoCaptureCandidate,
   PhotoCaptureCandidate,
   VideoCaptureCandidate,
 } from './capture_candidate.js';
@@ -431,11 +430,6 @@
       CaptureCandidate[] {
     const cameraInfo = this.cameraInfos.get(deviceId);
     assert(cameraInfo !== undefined);
-    const enableMultiStreamRecording =
-        expert.isEnabled(expert.ExpertOption.ENABLE_MULTISTREAM_RECORDING) ||
-        expert.isEnabled(
-            expert.ExpertOption.ENABLE_MULTISTREAM_RECORDING_CHROME);
-
     const candidates = [];
     const prefLevel = this.prefVideoResolutionLevelMap[deviceId];
     const prefResolution = this.prefVideoResolutionMap[deviceId] ?? null;
@@ -454,14 +448,8 @@
       const previewResolutions = videoPreviewPair.previewResolutions;
       for (const {constFps, resolutions} of option.fpsOptions) {
         for (const resolution of resolutions) {
-          let candidate;
-          if (enableMultiStreamRecording) {
-            candidate = new MultiStreamVideoCaptureCandidate(
-                deviceId, resolution, previewResolutions, constFps, hasAudio);
-          } else {
-            candidate = new VideoCaptureCandidate(
-                deviceId, resolution, previewResolutions, constFps, hasAudio);
-          }
+          const candidate = new VideoCaptureCandidate(
+              deviceId, resolution, previewResolutions, constFps, hasAudio);
           if (prefFps === constFps) {
             targetFpsCandidates.push(candidate);
           } else {
diff --git a/ash/webui/camera_app_ui/resources/js/device/device_monitor.ts b/ash/webui/camera_app_ui/resources/js/device/device_monitor.ts
new file mode 100644
index 0000000..5508ca0
--- /dev/null
+++ b/ash/webui/camera_app_ui/resources/js/device/device_monitor.ts
@@ -0,0 +1,163 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {reportError} from '../error.js';
+import {I18nString} from '../i18n_string.js';
+import * as loadTimeData from '../models/load_time_data.js';
+import {DeviceOperator} from '../mojo/device_operator.js';
+import {speak} from '../spoken_msg.js';
+import {ErrorLevel, ErrorType, VideoConfig} from '../type.js';
+import {sleep} from '../util.js';
+
+import {Camera3DeviceInfo} from './camera3_device_info.js';
+
+/**
+ * DeviceInfo includes MediaDeviceInfo and Camera3DeviceInfo.
+ */
+export interface DeviceInfo {
+  v1Info: MediaDeviceInfo;
+  v3Info: Camera3DeviceInfo|null;
+}
+
+/**
+ * Monitors device changes and provides different listener callbacks for
+ * device changes.
+ */
+export class DeviceMonitor {
+  /**
+   * Array of DeviceInfo of all available video devices.
+   */
+  private devicesInfo: DeviceInfo[] = [];
+
+  /**
+   * Array of listeners for device change event.
+   */
+  private readonly listeners: Array<(devices: DeviceInfo[]) => void> = [];
+
+  /**
+   * Filters out lagging 720p on grunt. See https://crbug.com/1122852.
+   */
+  private readonly videoConfigFilter: (config: VideoConfig) => boolean;
+
+  constructor() {
+    this.videoConfigFilter = (() => {
+      const board = loadTimeData.getBoard();
+      return board === 'grunt' ? ({height}: VideoConfig) => height < 720 :
+                                 () => true;
+    })();
+
+    navigator.mediaDevices.addEventListener(
+        'devicechange', () => this.deviceUpdate());
+  }
+
+  /**
+   * Registers listener to be called when state of available devices
+   * changes.
+   */
+  addDeviceChangeListener(listener: (devices: DeviceInfo[]) => void): void {
+    this.listeners.push(listener);
+  }
+
+  /**
+   * Handling function for device changing.
+   */
+  async deviceUpdate(): Promise<void> {
+    const devices = await this.doDeviceInfoUpdate();
+    if (devices === null) {
+      return;
+    }
+    this.doDeviceNotify(devices);
+  }
+
+  /**
+   * Updates devices information via mojo IPC.
+   */
+  private async doDeviceInfoUpdate(): Promise<DeviceInfo[]|null> {
+    try {
+      const devicesInfo = await this.enumerateDevices();
+      return await this.queryMojoDevicesInfo(devicesInfo);
+    } catch (e) {
+      if (loadTimeData.isVideoCaptureDisallowed()) {
+        // The failure is expected due to the policy so don't throw any error.
+        // TODO(b/297317408): Show messages on the UI.
+        // eslint-disable-next-line no-console
+        console.log('Failed to load camera since it is blocked by policy');
+      } else {
+        reportError(ErrorType.DEVICE_INFO_UPDATE_FAILURE, ErrorLevel.ERROR, e);
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Notifies device changes to listeners and creates a mapping for real and
+   * virtual device.
+   */
+  private doDeviceNotify(devices: DeviceInfo[]) {
+    let isDeviceChanged = false;
+    for (const added of this.getDifference(devices, this.devicesInfo)) {
+      speak(I18nString.STATUS_MSG_CAMERA_PLUGGED, added.v1Info.label);
+      isDeviceChanged = true;
+    }
+    for (const removed of this.getDifference(devices, this.devicesInfo)) {
+      speak(I18nString.STATUS_MSG_CAMERA_UNPLUGGED, removed.v1Info.label);
+      isDeviceChanged = true;
+    }
+    if (isDeviceChanged) {
+      for (const listener of this.listeners) {
+        listener(devices);
+      }
+    }
+    this.devicesInfo = devices;
+  }
+
+  /**
+   * Computes |devices| - |devices2|.
+   */
+  private getDifference(devices: DeviceInfo[], devices2: DeviceInfo[]):
+      DeviceInfo[] {
+    const ids = new Set(devices2.map((d) => d.v1Info.deviceId));
+    return devices.filter((d) => !ids.has(d.v1Info.deviceId));
+  }
+
+  /**
+   * Enumerates all available devices and gets their MediaDeviceInfo. Retries at
+   * one-second intervals if devices length is zero.
+   */
+  private async enumerateDevices(): Promise<MediaDeviceInfo[]> {
+    const deviceType = loadTimeData.getDeviceType();
+    const shouldHaveBuiltinCamera =
+        deviceType === 'chromebook' || deviceType === 'chromebase';
+    let attempts = 5;
+    while (attempts-- > 0) {
+      const devices = (await navigator.mediaDevices.enumerateDevices())
+                          .filter((device) => device.kind === 'videoinput');
+      if (!shouldHaveBuiltinCamera || devices.length > 0) {
+        return devices;
+      }
+      await sleep(1000);
+    }
+    throw new Error('Device list empty.');
+  }
+
+  /**
+   * Queries Camera3DeviceInfo of available devices through private mojo API.
+   *
+   * @return Camera3DeviceInfo of available devices. Maybe null on HALv1
+   *     devices without supporting private mojo api.
+   * @throws Thrown when camera unplugging happens between enumerating devices
+   *     and querying mojo APIs with current device info results.
+   */
+  private async queryMojoDevicesInfo(devices: MediaDeviceInfo[]):
+      Promise<DeviceInfo[]|null> {
+    const isV3Supported = DeviceOperator.isSupported();
+    return Promise.all(devices.map(
+        async (d) => ({
+          v1Info: d,
+          v3Info: isV3Supported ?
+              (await Camera3DeviceInfo.create(d, this.videoConfigFilter)) :
+              null,
+        })));
+  }
+}
diff --git a/ash/webui/camera_app_ui/resources/js/device/mode/index.ts b/ash/webui/camera_app_ui/resources/js/device/mode/index.ts
index 70807b0..6b26b7c 100644
--- a/ash/webui/camera_app_ui/resources/js/device/mode/index.ts
+++ b/ash/webui/camera_app_ui/resources/js/device/mode/index.ts
@@ -17,7 +17,6 @@
 } from '../../type.js';
 import {getFpsRangeFromConstraints} from '../../util.js';
 import {StreamConstraints} from '../stream_constraints.js';
-import {StreamManagerChrome} from '../stream_manager_chrome.js';
 
 import {
   ModeBase,
@@ -156,24 +155,6 @@
           const deviceId = constraints.deviceId;
           await deviceOperator.setCaptureIntent(
               deviceId, CaptureIntent.kVideoRecord);
-          await deviceOperator.setMultipleStreamsEnabled(
-              deviceId,
-              expert.isEnabled(
-                  expert.ExpertOption.ENABLE_MULTISTREAM_RECORDING),
-          );
-          if (expert.isEnabled(
-                  expert.ExpertOption.ENABLE_MULTISTREAM_RECORDING_CHROME)) {
-            const captureResolution =
-                assertExists(this.getCaptureParams().captureResolution);
-            await StreamManagerChrome.getInstance().prepare({
-              ...constraints,
-              video: {
-                ...constraints.video,
-                width: captureResolution.width,
-                height: captureResolution.height,
-              },
-            });
-          }
 
           if (await deviceOperator.isBlobVideoSnapshotEnabled(deviceId)) {
             await deviceOperator.setStillCaptureResolution(
diff --git a/ash/webui/camera_app_ui/resources/js/device/mode/video.ts b/ash/webui/camera_app_ui/resources/js/device/mode/video.ts
index 3d1832e..1c7bc18b 100644
--- a/ash/webui/camera_app_ui/resources/js/device/mode/video.ts
+++ b/ash/webui/camera_app_ui/resources/js/device/mode/video.ts
@@ -4,13 +4,11 @@
 
 import {
   assert,
-  assertExists,
   assertInstanceof,
 } from '../../assert.js';
 import {AsyncJobQueue} from '../../async_job_queue.js';
 import * a