diff --git a/AUTHORS b/AUTHORS
index 39e9b86..d2f9b1ee 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -841,6 +841,7 @@
 Luke Zarko <lukezarko@gmail.com>
 Luoxi Pan <l.panpax@gmail.com>
 Lu Yahan <yahan@iscas.ac.cn>
+Lyra Rebane <rebane2001@gmail.com>
 Ma Aiguo <imaiguo@gmail.com>
 Maarten Lankhorst <m.b.lankhorst@gmail.com>
 Maciej Pawlowski <m.pawlowski@eyeo.com>
diff --git a/DEPS b/DEPS
index a040289..f77c49c 100644
--- a/DEPS
+++ b/DEPS
@@ -241,7 +241,7 @@
   #
   # CQ_INCLUDE_TRYBOTS=luci.chrome.try:lacros-amd64-generic-chrome-skylab
   # CQ_INCLUDE_TRYBOTS=luci.chrome.try:lacros-arm-generic-chrome-skylab
-  'lacros_sdk_version': '15708.0.0',
+  'lacros_sdk_version': '15714.0.0',
 
   # Generate location tag metadata to include in tests result data uploaded
   # to ResultDB. This isn't needed on some configs and the tool that generates
@@ -307,7 +307,7 @@
   # 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': 'b8c5311b4088a044fc167fa2bf270fbdabf324e6',
+  'v8_revision': '457c0cbb2f97c9a56941eb48b95e0234d0739cd3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
@@ -354,7 +354,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
-  'freetype_revision': '8eab511017a65026985523cab14aff07f1bb9746',
+  'freetype_revision': 'ca76683b781db5d06ef1a0e2cb62a767e7dbe626',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
@@ -374,7 +374,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '2298e6389913688b2fee8100c4535053d627ef8c',
+  'catapult_revision': '61af87d894922b368c4733137916ecfaaa607fea',
   # 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.
@@ -394,7 +394,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': 'c67fdadcd104ba82740a25feed4fec2931b5f6f3',
+  'devtools_frontend_revision': '891806c2cf2bfe370e5e865269042afafbf9a569',
   # 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.
@@ -470,7 +470,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':    'c7c5649e8badcb31e66f188f5cf7933f9a8f8287',
+  'libcxxabi_revision':    '8806fb8bb26e20206241ea2dfcee4fd2d4157b83',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -494,7 +494,7 @@
 
   # If you change this, also update the libc++ revision in
   # //buildtools/deps_revisions.gni.
-  'libcxx_revision':       '28d7125795ff7da27512de569bb539e7ba44cb62',
+  'libcxx_revision':       'd855d8bc2ef4a063c552236b57ed0b1ab2e6e0c1',
 
   # GN CIPD package version.
   'gn_version': 'git_revision:85944ebc24a90ec1e489e85a46fdc68542c3146f',
@@ -818,12 +818,12 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '68277d9bc7d17ef27563d83fcc443e33fbeec22f',
+    'a2fed0cd29a5673211c8327dfd847830ebcbcb24',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
   'src/docs/website': {
-    'url': Var('chromium_git') + '/website.git' + '@' + 'b62ff6eb4a7f802e6bf27bb9e89248c94f095579',
+    'url': Var('chromium_git') + '/website.git' + '@' + '504421a2e612c9042411ae65e24d7a7682dfdbe2',
   },
 
   'src/ios/third_party/earl_grey2/src': {
@@ -980,7 +980,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': '4CxJZWo7ajrRGfWQCiweWMSo_Z-q6emYk1oHhobSdUoC',
+          'version': 'sqQJ-wARDWk_E32q9UOmDuZsVYv8ZVY37AD5jc996aYC',
       },
     ],
     'condition': 'checkout_android',
@@ -1155,7 +1155,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' + '@' + 'e8263ad9ebd447f97efbe1dee2df803ac0298ca9',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'd4083072a7a2976fcbbd44ed55dfac4d574c7497',
       'condition': 'checkout_chromeos',
   },
 
@@ -1196,7 +1196,7 @@
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
 
   'src/third_party/devtools-frontend-internal': {
-      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '457fec8b5b9ff390f9e7a8e64f8a886d97cbe1f9',
+      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '6b248f365bc8723b398e68704df495ecfbf3f8ee',
     'condition': 'checkout_src_internal',
   },
 
@@ -1661,7 +1661,7 @@
     Var('pdfium_git') + '/pdfium.git' + '@' +  Var('pdfium_revision'),
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '84bb6bced2420d2e7bd880cbf30b348448fa95d4',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '819068d7e83a09200ee0b3a43fe44d90465cca5e',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1846,7 +1846,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'eb1892c3e4ab734a135e8752f5442e270a4738d1',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'acdc89d65328911b4e98afe0757028eca162cbb3',
+    Var('webrtc_git') + '/src.git' + '@' + '2b311ea96a10b87cec66e2626ecadfa08dd868b1',
 
   # 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.
@@ -1980,7 +1980,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'wnZZLQ1PL9gD4zy6yFa_I96LRXsfE7KUDpp0bQgqBdUC',
+        'version': 'RuEryuccGQB0zXFAiqELjjw_hcvWFV9JH1wbFaZp6w0C',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -4003,7 +4003,7 @@
 
   'src/ios_internal':  {
       'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' +
-        'f94bc05bf5ee979b36eb2d58b336e469404524c1',
+        '5efd774964ac708dfd7625fc954f8c70391c79e6',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
@@ -4976,18 +4976,6 @@
                 '-s', 'src/third_party/gvr-android-sdk/test-libraries/controller_test_api.aar.sha1',
     ],
   },
-  {
-    'name': 'vr_assets',
-    'pattern': '.',
-    'condition': 'checkout_android and checkout_src_internal',
-    'action': ['python3',
-               'src/third_party/depot_tools/download_from_google_storage.py',
-               '--bucket', 'chrome-vr-assets',
-               '--recursive',
-               '--directory',
-               'src/chrome/browser/resources/vr/assets/google_chrome',
-    ],
-  },
   # Download and unpack MediaPipe Integration tests.
   {
     'name': 'mediapipe_integration_testdata',
@@ -5126,7 +5114,7 @@
       'src/third_party/chromite/bin/cros',
       'chrome-sdk',
       '--fallback-versions=20',
-      '--nogoma',
+      '--no-use-remoteexec',
       '--nogn-gen',
       '--no-shell',
       '--log-level=warning',
@@ -5145,7 +5133,7 @@
       'src/third_party/chromite/bin/cros',
       'chrome-sdk',
       '--fallback-versions=20',
-      '--nogoma',
+      '--no-use-remoteexec',
       '--nogn-gen',
       '--no-shell',
       '--log-level=warning',
@@ -5163,7 +5151,7 @@
       'src/third_party/chromite/bin/cros',
       'chrome-sdk',
       '--fallback-versions=20',
-      '--nogoma',
+      '--no-use-remoteexec',
       '--nogn-gen',
       '--no-shell',
       '--log-level=warning',
@@ -5180,7 +5168,7 @@
       'src/third_party/chromite/bin/cros',
       'chrome-sdk',
       '--fallback-versions=20',
-      '--nogoma',
+      '--no-use-remoteexec',
       '--nogn-gen',
       '--no-shell',
       '--log-level=warning',
@@ -5200,7 +5188,7 @@
       'src/third_party/chromite/bin/cros',
       'chrome-sdk',
       '--fallback-versions=20',
-      '--nogoma',
+      '--no-use-remoteexec',
       '--nogn-gen',
       '--no-shell',
       '--log-level=warning',
@@ -5220,7 +5208,7 @@
       'src/third_party/chromite/bin/cros',
       'chrome-sdk',
       '--fallback-versions=20',
-      '--nogoma',
+      '--no-use-remoteexec',
       '--nogn-gen',
       '--no-shell',
       '--log-level=warning',
@@ -5240,7 +5228,7 @@
       'src/third_party/chromite/bin/cros',
       'chrome-sdk',
       '--fallback-versions=20',
-      '--nogoma',
+      '--no-use-remoteexec',
       '--nogn-gen',
       '--no-shell',
       '--log-level=warning',
@@ -5259,7 +5247,7 @@
       'src/third_party/chromite/bin/cros',
       'chrome-sdk',
       '--fallback-versions=20',
-      '--nogoma',
+      '--no-use-remoteexec',
       '--nogn-gen',
       '--no-shell',
       '--log-level=warning',
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java
index a174c73a..c41f186 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java
@@ -35,6 +35,7 @@
 import org.chromium.base.test.util.Criteria;
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.CriteriaNotSatisfiedException;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.components.policy.AbstractAppRestrictionsProvider;
@@ -58,6 +59,7 @@
 /** Tests for the WebViewClient.shouldOverrideUrlLoading() method. */
 @RunWith(Parameterized.class)
 @UseParametersRunnerFactory(AwJUnit4ClassRunnerWithParameters.Factory.class)
+@DisabledTest(message = "Multiple test cases failing, crbug.com/1512112")
 public class AwContentsClientShouldOverrideUrlLoadingTest extends AwParameterizedTest {
     @Rule public AwActivityTestRule mActivityTestRule;
 
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/JsJavaInteractionTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/JsJavaInteractionTest.java
index a61022ffb..2468389 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/JsJavaInteractionTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/JsJavaInteractionTest.java
@@ -26,7 +26,6 @@
 import org.chromium.android_webview.test.TestAwContentsClient.OnReceivedTitleHelper;
 import org.chromium.android_webview.test.util.CommonResources;
 import org.chromium.base.test.util.Batch;
-import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
 import org.chromium.content_public.browser.MessagePayload;
 import org.chromium.content_public.browser.MessagePort;
@@ -64,8 +63,6 @@
             RESOURCE_PATH + "/post_message_array_buffer_reply.html";
     private static final String POST_MESSAGE_ARRAYBUFFER_TITLE_HTML =
             RESOURCE_PATH + "/post_message_array_buffer_title.html";
-    private static final String POST_MESSAGE_ARRAYBUFFER_TRANSFER_HTML =
-            RESOURCE_PATH + "/post_message_array_buffer_transfer.html";
     private static final String FILE_URI = "file:///android_asset/asset_file.html";
     private static final String HELLO_WORLD_HTML = RESOURCE_PATH + "/hello_world.html";
 
@@ -764,21 +761,6 @@
         Assert.assertTrue(mListener.hasNoMoreOnPostMessage());
     }
 
-    @Test
-    @MediumTest
-    @Feature({"AndroidWebView", "JsJavaInteraction"})
-    @CommandLineFlags.Add({"disable-features=JsInjectionArrayBufferJsToBrowser"})
-    public void testPostArrayBufferFeatureDisabled() throws Throwable {
-        final byte[] content = (HELLO + "FromJava").getBytes(StandardCharsets.UTF_8);
-        addWebMessageListenerOnUiThread(mAwContents, JS_OBJECT_NAME, new String[] {"*"}, mListener);
-        final String url = loadUrlFromPath(POST_MESSAGE_ARRAYBUFFER_REPLY_HTML);
-        TestWebMessageListener.Data data = mListener.waitForOnPostMessage();
-        data.mReplyProxy.postMessage(new MessagePayload(content));
-        data = mListener.waitForOnPostMessage();
-        final String errorString = data.getAsString();
-        Assert.assertTrue(errorString.contains("Error"));
-    }
-
     private void verifyPostArrayBufferWorks(byte[] content) throws Exception {
         addWebMessageListenerOnUiThread(mAwContents, JS_OBJECT_NAME, new String[] {"*"}, mListener);
         final String url = loadUrlFromPath(POST_MESSAGE_ARRAYBUFFER_REPLY_HTML);
@@ -814,7 +796,11 @@
         verifyPostArrayBufferWorks(content);
     }
 
-    private void verifyPostNullOrUndefinedShouldThrowException() throws Throwable {
+    @Test
+    @MediumTest
+    @Feature({"AndroidWebView", "JsJavaInteraction"})
+    public void testPostNullOrUndefinedShouldThrowExceptionWithArrayBufferFeature()
+            throws Throwable {
         final byte[] content = (HELLO + "FromJava").getBytes(StandardCharsets.UTF_8);
         addWebMessageListenerOnUiThread(mAwContents, JS_OBJECT_NAME, new String[] {"*"}, mListener);
         final String url = loadUrlFromPath(POST_MESSAGE_NULL_OR_UNDEFINED_HTML);
@@ -836,22 +822,6 @@
     @Test
     @MediumTest
     @Feature({"AndroidWebView", "JsJavaInteraction"})
-    @CommandLineFlags.Add({"disable-features=JsInjectionArrayBufferJsToBrowser"})
-    public void testPostNullOrUndefinedShouldThrowException() throws Throwable {
-        verifyPostNullOrUndefinedShouldThrowException();
-    }
-
-    @Test
-    @MediumTest
-    @Feature({"AndroidWebView", "JsJavaInteraction"})
-    public void testPostNullOrUndefinedShouldThrowExceptionWithArrayBufferFeature()
-            throws Throwable {
-        verifyPostNullOrUndefinedShouldThrowException();
-    }
-
-    @Test
-    @MediumTest
-    @Feature({"AndroidWebView", "JsJavaInteraction"})
     public void testJsReplyProxyReplyToTheCorrectJsObject() throws Throwable {
         final TestWebMessageListener webMessageListener2 = new TestWebMessageListener();
         addWebMessageListenerOnUiThread(mAwContents, JS_OBJECT_NAME, new String[] {"*"}, mListener);
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index f8d412f..fea52d2 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -686,6 +686,8 @@
     "glanceables/post_login_glanceables_metrics_recorder.h",
     "glanceables/tasks/glanceables_task_view.cc",
     "glanceables/tasks/glanceables_task_view.h",
+    "glanceables/tasks/glanceables_task_view_v2.cc",
+    "glanceables/tasks/glanceables_task_view_v2.h",
     "glanceables/tasks/glanceables_tasks_view.cc",
     "glanceables/tasks/glanceables_tasks_view.h",
     "host/ash_window_tree_host.cc",
@@ -3324,6 +3326,7 @@
     "glanceables/classroom/glanceables_classroom_item_view_unittest.cc",
     "glanceables/post_login_glanceables_metrics_recorder_unittest.cc",
     "glanceables/tasks/glanceables_task_view_unittest.cc",
+    "glanceables/tasks/glanceables_task_view_v2_unittest.cc",
     "glanceables/tasks/glanceables_tasks_view_unittest.cc",
     "host/ash_window_tree_host_platform_unittest.cc",
     "host/ash_window_tree_host_unified_unittest.cc",
diff --git a/ash/accelerators/accelerator_table.cc b/ash/accelerators/accelerator_table.cc
index 6131280e..4bbc0fb 100644
--- a/ash/accelerators/accelerator_table.cc
+++ b/ash/accelerators/accelerator_table.cc
@@ -497,11 +497,14 @@
     AcceleratorAction::kToggleMultitaskMenu,
 // clang-format on
 
-// AcceleratorAction::kOpenFeedbackPage is guarded by the BRANDING macro on
-// defining Browser's shortcuts. To follow it, guard it here, too.
+// kOpenFeedbackPage has two accelerators in browser:
+// 1: [alt shift i] guarded by GOOGLE_CHROME_BRANDING.
+// 2: [search ctrl i] guarded by both GOOGLE_CHROME_BRANDING and IS_CHROMEOS.
+// This file is built only for ash-chrome, so we only need to check BRANDING
+// macro.
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     AcceleratorAction::kOpenFeedbackPage,
-#endif
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 };
 
 const size_t kActionsDuplicatedWithBrowserLength =
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 583ac09d..f550dd55 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -3501,6 +3501,10 @@
   return base::FeatureList::IsEnabled(kGlanceablesV2ErrorMessage);
 }
 
+bool IsGlanceablesTimeManagementStableLaunchEnabled() {
+  return base::FeatureList::IsEnabled(kGlanceablesTimeManagementStableLaunch);
+}
+
 bool IsHibernateEnabled() {
   return base::FeatureList::IsEnabled(kHibernate);
 }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index e4e897d..5fc4f1f 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -1033,6 +1033,8 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsGlanceablesV2CalendarViewEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS)
 bool IsGlanceablesV2ErrorMessageEnabled();
+COMPONENT_EXPORT(ASH_CONSTANTS)
+bool IsGlanceablesTimeManagementStableLaunchEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHibernateEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHideArcMediaNotificationsEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHideShelfControlsInTabletModeEnabled();
diff --git a/ash/display/display_prefs.cc b/ash/display/display_prefs.cc
index 6104b35..6c52eb41 100644
--- a/ash/display/display_prefs.cc
+++ b/ash/display/display_prefs.cc
@@ -1002,4 +1002,15 @@
   StoreDisplayMixedMirrorModeParams(local_state_, mixed_params);
 }
 
+bool DisplayPrefs::IsDisplayAvailableInPref(int64_t display_id) const {
+  for (const auto it : local_state_->GetDict(prefs::kDisplayProperties)) {
+    int64_t id = display::kInvalidDisplayId;
+    if (base::StringToInt64(it.first, &id) && id == display_id) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
 }  // namespace ash
diff --git a/ash/display/display_prefs.h b/ash/display/display_prefs.h
index 32d7f89..0391d19f1 100644
--- a/ash/display/display_prefs.h
+++ b/ash/display/display_prefs.h
@@ -76,6 +76,10 @@
   void StoreDisplayMixedMirrorModeParamsForTest(
       const std::optional<display::MixedMirrorModeParams>& mixed_params);
 
+  // Checks if given `display_id` was saved to pref service before. Used to tell
+  // if a display is connected for the first time or not.
+  bool IsDisplayAvailableInPref(int64_t display_id) const;
+
  protected:
   friend class DisplayPrefsTest;
 
diff --git a/ash/display/display_prefs_unittest.cc b/ash/display/display_prefs_unittest.cc
index 1c38e1e..76b72228 100644
--- a/ash/display/display_prefs_unittest.cc
+++ b/ash/display/display_prefs_unittest.cc
@@ -1851,4 +1851,15 @@
               Optional(static_cast<int>(display::Display::ROTATE_0)));
 }
 
+TEST_F(DisplayPrefsTest, IsDisplayAvailableInPref) {
+  int64_t id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
+
+  // Display is not available in prefs before adding the display.
+  EXPECT_FALSE(display_prefs()->IsDisplayAvailableInPref(id));
+
+  // Display is available in prefs after adding the display.
+  UpdateDisplay("300x200");
+  EXPECT_TRUE(display_prefs()->IsDisplayAvailableInPref(id));
+}
+
 }  // namespace ash
diff --git a/ash/glanceables/glanceables_pixeltest.cc b/ash/glanceables/glanceables_pixeltest.cc
index 243a4ce..38642cf 100644
--- a/ash/glanceables/glanceables_pixeltest.cc
+++ b/ash/glanceables/glanceables_pixeltest.cc
@@ -97,8 +97,6 @@
 };
 
 // Pixel test for glanceables when no data is available.
-// Test disabled due to not taking dark/light mode into consideration.
-// http://b/294612234
 TEST_F(GlanceablesPixelTest, GlanceablesZeroState) {
   base::subtle::ScopedTimeClockOverrides time_override(
       []() {
@@ -123,8 +121,6 @@
 
 // Pixel test verifying initial UI for tasks glanceable as well as UI updates
 // when a task is marked as completed.
-// Test disabled due to not taking dark/light mode into consideration.
-// http://b/294612234
 TEST_F(GlanceablesPixelTest, GlanceablesTasksMarkAsCompleted) {
   base::subtle::ScopedTimeClockOverrides time_override(
       []() {
diff --git a/ash/glanceables/tasks/glanceables_task_view.cc b/ash/glanceables/tasks/glanceables_task_view.cc
index d2870287..d6525ef 100644
--- a/ash/glanceables/tasks/glanceables_task_view.cc
+++ b/ash/glanceables/tasks/glanceables_task_view.cc
@@ -376,6 +376,12 @@
       task_title_button_->UpdateLabelForState(/*completed=*/button_->checked());
       break;
     case TaskTitleViewState::kEdit:
+      // TODO(b/315188389): As there is a GlanceablesTaskViewV2 that replace
+      // this class when the stable launch flag is enabled, remove the
+      // adding/editing functions in this class to simplify the code.
+      if (!features::IsGlanceablesTimeManagementStableLaunchEnabled()) {
+        break;
+      }
       auto* const text_field =
           tasks_title_view_->AddChildView(std::make_unique<TaskViewTextField>(
               task_title_,
diff --git a/ash/glanceables/tasks/glanceables_task_view.h b/ash/glanceables/tasks/glanceables_task_view.h
index 4704f3761..4ad932c5 100644
--- a/ash/glanceables/tasks/glanceables_task_view.h
+++ b/ash/glanceables/tasks/glanceables_task_view.h
@@ -52,6 +52,8 @@
       api::TasksClient::OnTaskSavedCallback callback)>;
 
   // Modes of `tasks_title_view_` (simple label or text field).
+  // TODO(b/315188389): Remove this as editing functions is replaced by
+  // GlanceablesTaskViewV2 when the stable launch is enabled.
   enum class TaskTitleViewState { kView, kEdit };
 
   GlanceablesTaskView(const api::Task* task,
diff --git a/ash/glanceables/tasks/glanceables_task_view_unittest.cc b/ash/glanceables/tasks/glanceables_task_view_unittest.cc
index f7789e2..d3432512 100644
--- a/ash/glanceables/tasks/glanceables_task_view_unittest.cc
+++ b/ash/glanceables/tasks/glanceables_task_view_unittest.cc
@@ -80,71 +80,6 @@
   }
 }
 
-TEST_F(GlanceablesTaskViewTest, EntersAndExitsEditState) {
-  base::test::ScopedFeatureList features{
-      features::kGlanceablesTimeManagementStableLaunch};
-
-  const auto task = api::Task("task-id", "Task title", /*completed=*/false,
-                              /*due=*/std::nullopt,
-                              /*has_subtasks=*/false, /*has_email_link=*/false,
-                              /*has_notes=*/false, /*updated=*/base::Time());
-
-  const auto widget = CreateFramelessTestWidget();
-  widget->SetFullscreen(true);
-  const auto* const view =
-      widget->SetContentsView(std::make_unique<GlanceablesTaskView>(
-          &task, /*mark_as_completed_callback=*/base::DoNothing(),
-          /*save_callback=*/base::DoNothing()));
-
-  {
-    const auto* const title_label =
-        views::AsViewClass<views::Label>(view->GetViewByID(
-            base::to_underlying(GlanceablesViewId::kTaskItemTitleLabel)));
-    const auto* const title_text_field =
-        views::AsViewClass<views::Textfield>(view->GetViewByID(
-            base::to_underlying(GlanceablesViewId::kTaskItemTitleTextField)));
-
-    ASSERT_TRUE(title_label);
-    ASSERT_FALSE(title_text_field);
-    EXPECT_EQ(title_label->GetText(), u"Task title");
-
-    LeftClickOn(title_label);
-  }
-
-  {
-    const auto* const title_label =
-        views::AsViewClass<views::Label>(view->GetViewByID(
-            base::to_underlying(GlanceablesViewId::kTaskItemTitleLabel)));
-    const auto* const title_text_field =
-        views::AsViewClass<views::Textfield>(view->GetViewByID(
-            base::to_underlying(GlanceablesViewId::kTaskItemTitleTextField)));
-
-    ASSERT_FALSE(title_label);
-    ASSERT_TRUE(title_text_field);
-    EXPECT_EQ(title_text_field->GetText(), u"Task title");
-
-    PressAndReleaseKey(ui::VKEY_SPACE);
-    PressAndReleaseKey(ui::VKEY_U);
-    PressAndReleaseKey(ui::VKEY_P);
-    PressAndReleaseKey(ui::VKEY_D);
-
-    PressAndReleaseKey(ui::VKEY_ESCAPE);
-  }
-
-  {
-    const auto* const title_label =
-        views::AsViewClass<views::Label>(view->GetViewByID(
-            base::to_underlying(GlanceablesViewId::kTaskItemTitleLabel)));
-    const auto* const title_text_field =
-        views::AsViewClass<views::Textfield>(view->GetViewByID(
-            base::to_underlying(GlanceablesViewId::kTaskItemTitleTextField)));
-
-    ASSERT_TRUE(title_label);
-    ASSERT_FALSE(title_text_field);
-    EXPECT_EQ(title_label->GetText(), u"Task title upd");
-  }
-}
-
 TEST_F(GlanceablesTaskViewTest,
        AppliesStrikeThroughStyleAfterMarkingAsComplete) {
   const auto task = api::Task("task-id", "Task title", /*completed=*/false,
@@ -221,110 +156,4 @@
   }
 }
 
-TEST_F(GlanceablesTaskViewTest, InvokesSaveCallbackAfterAdding) {
-  base::test::TestFuture<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<GlanceablesTaskView>(
-          /*task=*/nullptr, /*mark_as_completed_callback=*/base::DoNothing(),
-          /*save_callback=*/future.GetRepeatingCallback()));
-  ASSERT_TRUE(view);
-
-  view->UpdateTaskTitleViewForState(
-      GlanceablesTaskView::TaskTitleViewState::kEdit);
-  PressAndReleaseKey(ui::VKEY_N, ui::EF_SHIFT_DOWN);
-  PressAndReleaseKey(ui::VKEY_E);
-  PressAndReleaseKey(ui::VKEY_W);
-  PressAndReleaseKey(ui::VKEY_ESCAPE);
-
-  const auto [task_id, title, callback] = future.Take();
-  EXPECT_TRUE(task_id.empty());
-  EXPECT_EQ(title, "New");
-}
-
-TEST_F(GlanceablesTaskViewTest, InvokesSaveCallbackAfterEditing) {
-  const auto task = api::Task("task-id", "Task title", /*completed=*/false,
-                              /*due=*/std::nullopt,
-                              /*has_subtasks=*/false, /*has_email_link=*/false,
-                              /*has_notes=*/false, /*updated=*/base::Time());
-
-  base::test::TestFuture<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<GlanceablesTaskView>(
-          &task, /*mark_as_completed_callback=*/base::DoNothing(),
-          /*save_callback=*/future.GetRepeatingCallback()));
-  ASSERT_TRUE(view);
-
-  view->UpdateTaskTitleViewForState(
-      GlanceablesTaskView::TaskTitleViewState::kEdit);
-  PressAndReleaseKey(ui::VKEY_SPACE);
-  PressAndReleaseKey(ui::VKEY_U);
-  PressAndReleaseKey(ui::VKEY_P);
-  PressAndReleaseKey(ui::VKEY_D);
-  PressAndReleaseKey(ui::VKEY_ESCAPE);
-
-  const auto [task_id, title, callback] = future.Take();
-  EXPECT_EQ(task_id, "task-id");
-  EXPECT_EQ(title, "Task title upd");
-}
-
-TEST_F(GlanceablesTaskViewTest, SupportsEditingRightAfterAdding) {
-  base::test::TestFuture<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<GlanceablesTaskView>(
-          /*task=*/nullptr, /*mark_as_completed_callback=*/base::DoNothing(),
-          /*save_callback=*/future.GetRepeatingCallback()));
-  ASSERT_TRUE(view);
-
-  {
-    view->UpdateTaskTitleViewForState(
-        GlanceablesTaskView::TaskTitleViewState::kEdit);
-    PressAndReleaseKey(ui::VKEY_N, ui::EF_SHIFT_DOWN);
-    PressAndReleaseKey(ui::VKEY_E);
-    PressAndReleaseKey(ui::VKEY_W);
-    PressAndReleaseKey(ui::VKEY_ESCAPE);
-
-    // Verify that `task_id` is empty after adding a task.
-    auto [task_id, title, callback] = future.Take();
-    EXPECT_TRUE(task_id.empty());
-    EXPECT_EQ(title, "New");
-
-    // Simulate reply, the view should update itself with the new task id.
-    const auto created_task =
-        api::Task("task-id", "New", /*completed=*/false,
-                  /*due=*/absl::nullopt,
-                  /*has_subtasks=*/false,
-                  /*has_email_link=*/false, /*has_notes=*/false,
-                  /*updated=*/base::Time::Now());
-    std::move(callback).Run(&created_task);
-  }
-
-  {
-    view->UpdateTaskTitleViewForState(
-        GlanceablesTaskView::TaskTitleViewState::kEdit);
-    PressAndReleaseKey(ui::VKEY_SPACE);
-    PressAndReleaseKey(ui::VKEY_1);
-    PressAndReleaseKey(ui::VKEY_ESCAPE);
-
-    // Verify that `task_id` equals to "task-id" after editing the same task.
-    const auto [task_id, title, callback] = future.Take();
-    EXPECT_EQ(task_id, "task-id");
-    EXPECT_EQ(title, "New 1");
-  }
-}
-
 }  // namespace ash
diff --git a/ash/glanceables/tasks/glanceables_task_view_v2.cc b/ash/glanceables/tasks/glanceables_task_view_v2.cc
new file mode 100644
index 0000000..5883455
--- /dev/null
+++ b/ash/glanceables/tasks/glanceables_task_view_v2.cc
@@ -0,0 +1,420 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/glanceables/tasks/glanceables_task_view_v2.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "ash/api/tasks/tasks_types.h"
+#include "ash/constants/ash_features.h"
+#include "ash/glanceables/common/glanceables_view_id.h"
+#include "ash/glanceables/glanceables_metrics.h"
+#include "ash/resources/vector_icons/vector_icons.h"
+#include "ash/shell.h"
+#include "ash/strings/grit/ash_strings.h"
+#include "ash/style/typography.h"
+#include "ash/system/time/calendar_utils.h"
+#include "ash/system/time/date_helper.h"
+#include "base/feature_list.h"
+#include "base/functional/bind.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/types/cxx23_to_underlying.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/metadata/metadata_header_macros.h"
+#include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
+#include "ui/events/keycodes/keyboard_codes_posix.h"
+#include "ui/events/types/event_type.h"
+#include "ui/gfx/font.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/vector_icon_types.h"
+#include "ui/views/accessibility/view_accessibility.h"
+#include "ui/views/background.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/button/label_button.h"
+#include "ui/views/controls/focus_ring.h"
+#include "ui/views/controls/image_view.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/controls/textfield/textfield_controller.h"
+#include "ui/views/layout/flex_layout_view.h"
+#include "ui/views/widget/widget_delegate.h"
+
+namespace ash {
+namespace {
+
+constexpr int kIconSize = 20;
+constexpr char kFormatterPattern[] = "EEE, MMM d";  // "Wed, Feb 28"
+
+constexpr auto kSecondRowItemsMargin = gfx::Insets::TLBR(0, 0, 0, 4);
+
+constexpr auto kSingleRowButtonMargin = gfx::Insets::VH(13, 6);
+constexpr auto kDoubleRowButtonMargin = gfx::Insets::VH(16, 6);
+
+constexpr auto kSingleRowTextMargins = gfx::Insets::TLBR(13, 13, 13, 16);
+constexpr auto kDoubleRowTextMargins = gfx::Insets::TLBR(7, 13, 7, 16);
+
+views::Label* SetupLabel(views::View* parent) {
+  views::Label* label = parent->AddChildView(std::make_unique<views::Label>());
+  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->SetBackgroundColor(SK_ColorTRANSPARENT);
+  label->SetAutoColorReadabilityEnabled(false);
+  return label;
+}
+
+std::u16string GetFormattedDueDate(const base::Time& due) {
+  // Google Tasks API does not respect time portion of the date and always
+  // returns "YYYY-MM-DDT00:00:00.000Z" format (see "due" field
+  // https://developers.google.com/tasks/reference/rest/v1/tasks). Treating this
+  // date in UTC format as is leads to showing one day less in timezones to the
+  // west of UTC. The following line adjusts `due` so that it becomes a
+  // **local** midnight instead.
+  const auto adjusted_due = due - calendar_utils::GetTimeDifference(due);
+  const auto midnight_today = base::Time::Now().LocalMidnight();
+  const auto midnight_tomorrow = midnight_today + base::Days(1);
+
+  if (midnight_today <= adjusted_due && adjusted_due < midnight_tomorrow) {
+    return l10n_util::GetStringUTF16(IDS_GLANCEABLES_DUE_TODAY);
+  }
+
+  auto* const date_helper = DateHelper::GetInstance();
+  CHECK(date_helper);
+  const auto formatter =
+      date_helper->CreateSimpleDateFormatter(kFormatterPattern);
+  return date_helper->GetFormattedTime(&formatter, adjusted_due);
+}
+
+std::unique_ptr<views::ImageView> CreateSecondRowIcon(
+    const gfx::VectorIcon& icon) {
+  auto icon_view = std::make_unique<views::ImageView>();
+  icon_view->SetProperty(views::kMarginsKey, kSecondRowItemsMargin);
+  icon_view->SetImage(ui::ImageModel::FromVectorIcon(
+      icon, cros_tokens::kCrosSysOnSurfaceVariant));
+  return icon_view;
+}
+
+class TaskViewTextField : public views::Textfield,
+                          public views::TextfieldController {
+  METADATA_HEADER(TaskViewTextField, views::Textfield)
+
+ public:
+  using OnFinishedEditingCallback =
+      base::OnceCallback<void(const std::u16string& title)>;
+
+  TaskViewTextField(const std::u16string& title,
+                    OnFinishedEditingCallback on_finished_editing)
+      : on_finished_editing_(std::move(on_finished_editing)) {
+    SetAccessibleName(u"[l10n] Title");
+    SetBackgroundColor(SK_ColorTRANSPARENT);
+    SetBorder(nullptr);
+    SetController(this);
+    SetID(base::to_underlying(GlanceablesViewId::kTaskItemTitleTextField));
+    SetPlaceholderText(u"[l10n] Title");
+    SetText(title);
+  }
+  TaskViewTextField(const TaskViewTextField&) = delete;
+  TaskViewTextField& operator=(const TaskViewTextField&) = delete;
+  ~TaskViewTextField() override = default;
+
+  // views::Textfield:
+  gfx::Size CalculatePreferredSize() const override {
+    return gfx::Size(0, GetFontList().GetHeight());
+  }
+
+  // views::TextfieldController:
+  bool HandleKeyEvent(views::Textfield* sender,
+                      const ui::KeyEvent& key_event) override {
+    if (key_event.type() == ui::ET_KEY_PRESSED &&
+        (key_event.key_code() == ui::VKEY_ESCAPE ||
+         key_event.key_code() == ui::VKEY_RETURN)) {
+      OnFinishedEditing();
+      return true;
+    }
+    return views::TextfieldController::HandleKeyEvent(sender, key_event);
+  }
+
+  // TODO(b/301253574): implement other triggers to run the callback:
+  // - tab navigation away from the text field;
+  // - mouse click outside.
+
+ private:
+  void OnFinishedEditing() {
+    // Running `on_finished_editing_` deletes `this`.
+    std::move(on_finished_editing_).Run(GetText());
+  }
+
+  OnFinishedEditingCallback on_finished_editing_;
+};
+
+BEGIN_METADATA(TaskViewTextField)
+END_METADATA
+
+}  // namespace
+
+class GlanceablesTaskViewV2::CheckButton : public views::ImageButton {
+  METADATA_HEADER(CheckButton, views::ImageButton)
+
+ public:
+  explicit CheckButton(PressedCallback pressed_callback)
+      : views::ImageButton(std::move(pressed_callback)) {
+    SetAccessibleRole(ax::mojom::Role::kCheckBox);
+    UpdateImage();
+    SetFlipCanvasOnPaintForRTLUI(/*enable=*/false);
+    views::FocusRing::Get(this)->SetColorId(cros_tokens::kCrosSysFocusRing);
+  }
+
+  void GetAccessibleNodeData(ui::AXNodeData* node_data) override {
+    views::ImageButton::GetAccessibleNodeData(node_data);
+
+    node_data->SetName(l10n_util::GetStringUTF16(
+        checked_
+            ? IDS_GLANCEABLES_TASKS_TASK_ITEM_MARK_NOT_COMPLETED_ACCESSIBLE_NAME
+            : IDS_GLANCEABLES_TASKS_TASK_ITEM_MARK_COMPLETED_ACCESSIBLE_NAME));
+
+    const ax::mojom::CheckedState checked_state =
+        checked_ ? ax::mojom::CheckedState::kTrue
+                 : ax::mojom::CheckedState::kFalse;
+    node_data->SetCheckedState(checked_state);
+    node_data->SetDefaultActionVerb(checked_
+                                        ? ax::mojom::DefaultActionVerb::kUncheck
+                                        : ax::mojom::DefaultActionVerb::kCheck);
+  }
+
+  void SetChecked(bool checked) {
+    checked_ = checked;
+    UpdateImage();
+    NotifyAccessibilityEvent(ax::mojom::Event::kCheckedStateChanged, true);
+  }
+
+  bool checked() const { return checked_; }
+
+ private:
+  void UpdateImage() {
+    SetImageModel(
+        views::Button::STATE_NORMAL,
+        ui::ImageModel::FromVectorIcon(
+            checked_ ? ash::kHollowCheckCircleIcon : ash::kHollowCircleIcon,
+            cros_tokens::kFocusRingColor, kIconSize));
+  }
+
+  bool checked_ = false;
+};
+
+BEGIN_METADATA(GlanceablesTaskViewV2, CheckButton, views::ImageButton)
+END_METADATA
+
+class GlanceablesTaskViewV2::TaskTitleButton : public views::LabelButton {
+  METADATA_HEADER(TaskTitleButton, views::LabelButton)
+
+ public:
+  TaskTitleButton(const std::u16string& title, PressedCallback pressed_callback)
+      : views::LabelButton(std::move(pressed_callback), title) {
+    SetBorder(nullptr);
+
+    label()->SetID(base::to_underlying(GlanceablesViewId::kTaskItemTitleLabel));
+    label()->SetLineHeight(TypographyProvider::Get()->ResolveLineHeight(
+        TypographyToken::kCrosButton2));
+  }
+
+  void UpdateLabelForState(bool completed) {
+    const auto color_id = completed ? cros_tokens::kCrosSysSecondary
+                                    : cros_tokens::kCrosSysOnSurface;
+    SetEnabledTextColorIds(color_id);
+    label()->SetFontList(
+        TypographyProvider::Get()
+            ->ResolveTypographyToken(TypographyToken::kCrosButton2)
+            .DeriveWithStyle(completed ? gfx::Font::FontStyle::STRIKE_THROUGH
+                                       : gfx::Font::FontStyle::NORMAL));
+  }
+};
+
+BEGIN_METADATA(GlanceablesTaskViewV2, TaskTitleButton, views::LabelButton)
+END_METADATA
+
+GlanceablesTaskViewV2::GlanceablesTaskViewV2(
+    const api::Task* task,
+    MarkAsCompletedCallback mark_as_completed_callback,
+    SaveCallback save_callback)
+    : task_id_(task ? task->id : ""),
+      task_title_(task ? base::UTF8ToUTF16(task->title) : u""),
+      mark_as_completed_callback_(std::move(mark_as_completed_callback)),
+      save_callback_(std::move(save_callback)) {
+  CHECK(features::IsGlanceablesTimeManagementStableLaunchEnabled());
+  SetAccessibleRole(ax::mojom::Role::kListItem);
+
+  SetCrossAxisAlignment(views::LayoutAlignment::kStart);
+  SetOrientation(views::LayoutOrientation::kHorizontal);
+
+  button_ = AddChildView(std::make_unique<CheckButton>(base::BindRepeating(
+      &GlanceablesTaskViewV2::CheckButtonPressed, base::Unretained(this))));
+
+  contents_view_ = AddChildView(std::make_unique<views::FlexLayoutView>());
+  contents_view_->SetCrossAxisAlignment(views::LayoutAlignment::kStretch);
+  contents_view_->SetMainAxisAlignment(views::LayoutAlignment::kCenter);
+  contents_view_->SetOrientation(views::LayoutOrientation::kVertical);
+  contents_view_->SetProperty(
+      views::kFlexBehaviorKey,
+      views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToZero,
+                               views::MaximumFlexSizeRule::kUnbounded));
+
+  tasks_title_view_ =
+      contents_view_->AddChildView(std::make_unique<views::FlexLayoutView>());
+  tasks_title_view_->SetDefault(
+      views::kFlexBehaviorKey,
+      views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToZero,
+                               views::MaximumFlexSizeRule::kUnbounded));
+
+  tasks_details_view_ =
+      contents_view_->AddChildView(std::make_unique<views::FlexLayoutView>());
+  tasks_details_view_->SetCrossAxisAlignment(views::LayoutAlignment::kCenter);
+  tasks_details_view_->SetOrientation(views::LayoutOrientation::kHorizontal);
+
+  UpdateTaskTitleViewForState(TaskTitleViewState::kView);
+
+  std::vector<std::u16string> details;
+  if (task && task->due.has_value()) {
+    tasks_details_view_->AddChildView(
+        CreateSecondRowIcon(kGlanceablesTasksDueDateIcon));
+
+    const auto formatted_due_date = GetFormattedDueDate(task->due.value());
+    details.push_back(l10n_util::GetStringFUTF16(
+        IDS_GLANCEABLES_TASKS_TASK_ITEM_HAS_DUE_DATE_ACCESSIBLE_DESCRIPTION,
+        formatted_due_date));
+
+    views::Label* due_date_label = SetupLabel(tasks_details_view_);
+    due_date_label->SetText(formatted_due_date);
+    due_date_label->SetID(
+        base::to_underlying(GlanceablesViewId::kTaskItemDueLabel));
+    due_date_label->SetProperty(views::kMarginsKey, kSecondRowItemsMargin);
+    due_date_label->SetFontList(
+        TypographyProvider::Get()->ResolveTypographyToken(
+            TypographyToken::kCrosAnnotation1));
+    due_date_label->SetLineHeight(TypographyProvider::Get()->ResolveLineHeight(
+        TypographyToken::kCrosAnnotation1));
+    due_date_label->SetEnabledColorId(cros_tokens::kCrosSysOnSurfaceVariant);
+  }
+
+  if (task && task->has_subtasks) {
+    details.push_back(l10n_util::GetStringUTF16(
+        IDS_GLANCEABLES_TASKS_TASK_ITEM_HAS_SUBTASK_ACCESSIBLE_DESCRIPTION));
+    tasks_details_view_->AddChildView(
+        CreateSecondRowIcon(kGlanceablesSubtaskIcon));
+  }
+
+  if (task && task->has_notes) {
+    details.push_back(l10n_util::GetStringUTF16(
+        IDS_GLANCEABLES_TASKS_TASK_ITEM_HAS_DETAILS_ACCESSIBLE_DESCRIPTION));
+    tasks_details_view_->AddChildView(
+        CreateSecondRowIcon(kGlanceablesTasksNotesIcon));
+  }
+
+  // Use different margins depending on the number of
+  // rows of text shown.
+  const bool double_row = tasks_details_view_->children().size() > 0;
+  contents_view_->SetProperty(views::kMarginsKey, double_row
+                                                      ? kDoubleRowTextMargins
+                                                      : kSingleRowTextMargins);
+  button_->SetProperty(views::kMarginsKey, double_row ? kDoubleRowButtonMargin
+                                                      : kSingleRowButtonMargin);
+
+  auto a11y_description = task_title_;
+  if (!details.empty()) {
+    a11y_description += u". ";
+    a11y_description += l10n_util::GetStringFUTF16(
+        IDS_GLANCEABLES_TASKS_TASK_ITEM_METADATA_WRAPPER_ACCESSIBLE_DESCRIPTION,
+        base::JoinString(details, u", "));
+  }
+  button_->SetAccessibleDescription(a11y_description);
+  button_->NotifyAccessibilityEvent(ax::mojom::Event::kTextChanged, true);
+}
+
+GlanceablesTaskViewV2::~GlanceablesTaskViewV2() = default;
+
+const views::ImageButton* GlanceablesTaskViewV2::GetCheckButtonForTest() const {
+  return button_;
+}
+
+bool GlanceablesTaskViewV2::GetCompletedForTest() const {
+  return button_->checked();
+}
+
+void GlanceablesTaskViewV2::UpdateTaskTitleViewForState(
+    TaskTitleViewState state) {
+  task_title_button_ = nullptr;
+  tasks_title_view_->RemoveAllChildViews();
+
+  switch (state) {
+    case TaskTitleViewState::kView:
+      task_title_button_ =
+          tasks_title_view_->AddChildView(std::make_unique<TaskTitleButton>(
+              task_title_, base::BindRepeating(
+                               &GlanceablesTaskViewV2::TaskTitleButtonPressed,
+                               base::Unretained(this))));
+      task_title_button_->UpdateLabelForState(/*completed=*/button_->checked());
+      break;
+    case TaskTitleViewState::kEdit:
+      auto* const text_field =
+          tasks_title_view_->AddChildView(std::make_unique<TaskViewTextField>(
+              task_title_,
+              base::BindOnce(&GlanceablesTaskViewV2::OnFinishedEditing,
+                             base::Unretained(this))));
+      GetWidget()->widget_delegate()->SetCanActivate(true);
+      text_field->RequestFocus();
+      break;
+  }
+}
+
+void GlanceablesTaskViewV2::CheckButtonPressed() {
+  bool target_state = !button_->checked();
+  // Visually mark the task as completed.
+  button_->SetChecked(target_state);
+  if (task_title_button_) {
+    task_title_button_->UpdateLabelForState(/*completed=*/target_state);
+  }
+  RecordTaskMarkedAsCompleted(target_state);
+  mark_as_completed_callback_.Run(task_id_, /*completed=*/target_state);
+}
+
+void GlanceablesTaskViewV2::TaskTitleButtonPressed() {
+  // TODO(b/301253574): notify siblings to switch to `kView`.
+  UpdateTaskTitleViewForState(TaskTitleViewState::kEdit);
+}
+
+void GlanceablesTaskViewV2::OnFinishedEditing(const std::u16string& title) {
+  const auto old_title = task_title_;
+  if (!title.empty()) {
+    task_title_ = title;
+  }
+
+  UpdateTaskTitleViewForState(TaskTitleViewState::kView);
+
+  if (task_id_.empty() || task_title_ != old_title) {
+    save_callback_.Run(task_id_, base::UTF16ToUTF8(task_title_),
+                       base::BindOnce(&GlanceablesTaskViewV2::OnSaved,
+                                      weak_ptr_factory_.GetWeakPtr()));
+    // TODO(b/301253574): introduce "disabled" state for this view to prevent
+    // editing / marking as complete while the task is not fully created yet and
+    // race conditions while editing the same task.
+  }
+}
+
+void GlanceablesTaskViewV2::OnSaved(const api::Task* task) {
+  if (!task) {
+    return;
+  }
+  task_id_ = task->id;
+}
+
+BEGIN_METADATA(GlanceablesTaskViewV2, views::View)
+END_METADATA
+
+}  // namespace ash
diff --git a/ash/glanceables/tasks/glanceables_task_view_v2.h b/ash/glanceables/tasks/glanceables_task_view_v2.h
new file mode 100644
index 0000000..ae6f58d7
--- /dev/null
+++ b/ash/glanceables/tasks/glanceables_task_view_v2.h
@@ -0,0 +1,112 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_GLANCEABLES_TASKS_GLANCEABLES_TASK_VIEW_V2_H_
+#define ASH_GLANCEABLES_TASKS_GLANCEABLES_TASK_VIEW_V2_H_
+
+#include <string>
+
+#include "ash/api/tasks/tasks_client.h"
+#include "ash/ash_export.h"
+#include "base/functional/callback_forward.h"
+#include "base/memory/raw_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "ui/base/metadata/metadata_header_macros.h"
+#include "ui/views/layout/flex_layout_view.h"
+
+namespace views {
+class ImageButton;
+}  // namespace views
+
+namespace ash {
+
+namespace api {
+struct Task;
+}  // namespace api
+
+// GlanceablesTaskViewV2 uses `views::FlexLayout` to show tasks metadata within
+// the `GlanceablesTasksView` or `TasksBubbleView`.
+// +---------------------------------------------------------------+
+// |`GlanceablesTaskViewV2`                                          |
+// |                                                               |
+// | +-----------------+ +---------------------------------------+ |
+// | |'button_'        | |'contents_view_'                       | |
+// | |                 | | +-----------------------------------+ | |
+// | |                 | | |'tasks_title_view_'                | | |
+// | |                 | | +-----------------------------------+ | |
+// | |                 | | +-----------------------------------+ | |
+// | |                 | | |'tasks_details_view_'              | | |
+// | |                 | | +-----------------------------------+ | |
+// | +-----------------+ +---------------------------------------+ |
+// +---------------------------------------------------------------+
+class ASH_EXPORT GlanceablesTaskViewV2 : public views::FlexLayoutView {
+ public:
+  METADATA_HEADER(GlanceablesTaskViewV2);
+
+  using MarkAsCompletedCallback =
+      base::RepeatingCallback<void(const std::string& task_id, bool completed)>;
+  using SaveCallback = base::RepeatingCallback<void(
+      const std::string& task_id,
+      const std::string& title,
+      api::TasksClient::OnTaskSavedCallback callback)>;
+
+  // Modes of `tasks_title_view_` (simple label or text field).
+  enum class TaskTitleViewState { kView, kEdit };
+
+  GlanceablesTaskViewV2(const api::Task* task,
+                        MarkAsCompletedCallback mark_as_completed_callback,
+                        SaveCallback save_callback);
+  GlanceablesTaskViewV2(const GlanceablesTaskViewV2&) = delete;
+  GlanceablesTaskViewV2& operator=(const GlanceablesTaskViewV2&) = delete;
+  ~GlanceablesTaskViewV2() override;
+
+  const views::ImageButton* GetCheckButtonForTest() const;
+  bool GetCompletedForTest() const;
+
+  // Updates `tasks_title_view_` according to `state`.
+  void UpdateTaskTitleViewForState(TaskTitleViewState state);
+
+ private:
+  class CheckButton;
+  class TaskTitleButton;
+
+  // Handles press events on `button_`.
+  void CheckButtonPressed();
+
+  // Handles press events on `task_title_button_`.
+  void TaskTitleButtonPressed();
+
+  // Handles finished editing event from the text field, updates `task_title_`
+  // and propagates new `title` to the server.
+  void OnFinishedEditing(const std::u16string& title);
+
+  // Handles completion of running `save_callback_` callback.
+  // `task` - newly created or updated task.
+  void OnSaved(const api::Task* task);
+
+  // Owned by views hierarchy.
+  raw_ptr<CheckButton> button_ = nullptr;
+  raw_ptr<views::FlexLayoutView, ExperimentalAsh> contents_view_ = nullptr;
+  raw_ptr<views::FlexLayoutView, ExperimentalAsh> tasks_title_view_ = nullptr;
+  raw_ptr<TaskTitleButton, ExperimentalAsh> task_title_button_ = nullptr;
+  raw_ptr<views::FlexLayoutView, ExperimentalAsh> tasks_details_view_ = nullptr;
+
+  // ID for the task represented by this view.
+  std::string task_id_;
+
+  // Title of the task.
+  std::u16string task_title_;
+
+  // Marks the task as completed.
+  const MarkAsCompletedCallback mark_as_completed_callback_;
+
+  // Saves the task (either creates or updates the existing one).
+  const SaveCallback save_callback_;
+
+  base::WeakPtrFactory<GlanceablesTaskViewV2> weak_ptr_factory_{this};
+};
+
+}  // namespace ash
+
+#endif  // ASH_GLANCEABLES_TASKS_GLANCEABLES_TASK_VIEW_V2_H_
diff --git a/ash/glanceables/tasks/glanceables_task_view_v2_unittest.cc b/ash/glanceables/tasks/glanceables_task_view_v2_unittest.cc
new file mode 100644
index 0000000..e764949
--- /dev/null
+++ b/ash/glanceables/tasks/glanceables_task_view_v2_unittest.cc
@@ -0,0 +1,341 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/glanceables/tasks/glanceables_task_view_v2.h"
+
+#include <memory>
+#include <optional>
+#include <string>
+
+#include "ash/api/tasks/tasks_client.h"
+#include "ash/api/tasks/tasks_types.h"
+#include "ash/constants/ash_features.h"
+#include "ash/glanceables/common/glanceables_view_id.h"
+#include "ash/system/time/calendar_unittest_utils.h"
+#include "ash/test/ash_test_base.h"
+#include "base/functional/callback_helpers.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/test_future.h"
+#include "base/time/time.h"
+#include "base/time/time_override.h"
+#include "base/types/cxx23_to_underlying.h"
+#include "chromeos/ash/components/settings/scoped_timezone_settings.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/keycodes/keyboard_codes_posix.h"
+#include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/view_utils.h"
+#include "ui/views/widget/widget.h"
+
+namespace ash {
+
+class GlanceablesTaskViewStableLaunchTest : public AshTestBase {
+ public:
+  GlanceablesTaskViewStableLaunchTest() {
+    feature_list_.InitWithFeatures(
+        /*enabled_features=*/{features::kGlanceablesV2,
+                              features::kGlanceablesTimeManagementStableLaunch},
+        /*disabled_features=*/{});
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+TEST_F(GlanceablesTaskViewStableLaunchTest, FormatsDueDate) {
+  base::subtle::ScopedTimeClockOverrides time_override(
+      []() {
+        base::Time now;
+        EXPECT_TRUE(base::Time::FromString("2022-12-21T13:25:00.000Z", &now));
+        return now;
+      },
+      nullptr, nullptr);
+
+  struct {
+    std::string due;
+    std::string time_zone;
+    std::u16string expected_text;
+  } test_cases[] = {
+      {"2022-12-21T00:00:00.000Z", "America/New_York", u"Today"},
+      {"2022-12-21T00:00:00.000Z", "Europe/Oslo", u"Today"},
+      {"2022-12-30T00:00:00.000Z", "America/New_York", u"Fri, Dec 30"},
+      {"2022-12-30T00:00:00.000Z", "Europe/Oslo", u"Fri, Dec 30"},
+  };
+
+  for (const auto& tc : test_cases) {
+    // 1 - for ICU formatters; 2 - for `base::Time::LocalExplode`.
+    system::ScopedTimezoneSettings tz(base::UTF8ToUTF16(tc.time_zone));
+    calendar_test_utils::ScopedLibcTimeZone libc_tz(tc.time_zone);
+
+    base::Time due;
+    EXPECT_TRUE(base::Time::FromString(tc.due.c_str(), &due));
+
+    const auto task = api::Task("task-id", "Task title", /*completed=*/false,
+                                /*due=*/due,
+                                /*has_subtasks=*/false,
+                                /*has_email_link=*/false, /*has_notes=*/false,
+                                /*updated=*/due);
+    const auto view = GlanceablesTaskViewV2(
+        &task, /*mark_as_completed_callback=*/base::DoNothing(),
+        /*save_callback=*/base::DoNothing());
+
+    const auto* const due_label =
+        views::AsViewClass<views::Label>(view.GetViewByID(
+            base::to_underlying(GlanceablesViewId::kTaskItemDueLabel)));
+    ASSERT_TRUE(due_label);
+
+    EXPECT_EQ(due_label->GetText(), tc.expected_text);
+  }
+}
+
+TEST_F(GlanceablesTaskViewStableLaunchTest,
+       AppliesStrikeThroughStyleAfterMarkingAsComplete) {
+  const auto task = api::Task("task-id", "Task title", /*completed=*/false,
+                              /*due=*/std::nullopt,
+                              /*has_subtasks=*/false, /*has_email_link=*/false,
+                              /*has_notes=*/false, /*updated=*/base::Time());
+
+  const auto widget = CreateFramelessTestWidget();
+  widget->SetFullscreen(true);
+  const auto* const view =
+      widget->SetContentsView(std::make_unique<GlanceablesTaskViewV2>(
+          &task, /*mark_as_completed_callback=*/base::DoNothing(),
+          /*save_callback=*/base::DoNothing()));
+  ASSERT_TRUE(view);
+
+  const auto* const checkbox = view->GetCheckButtonForTest();
+  ASSERT_TRUE(checkbox);
+
+  const auto* const title_label =
+      views::AsViewClass<views::Label>(view->GetViewByID(
+          base::to_underlying(GlanceablesViewId::kTaskItemTitleLabel)));
+  ASSERT_TRUE(title_label);
+
+  // No `STRIKE_THROUGH` style applied initially.
+  EXPECT_FALSE(view->GetCompletedForTest());
+  EXPECT_FALSE(title_label->font_list().GetFontStyle() &
+               gfx::Font::FontStyle::STRIKE_THROUGH);
+
+  // After pressing on `checkbox`, the label should have `STRIKE_THROUGH` style
+  // applied.
+  GestureTapOn(checkbox);
+  EXPECT_TRUE(view->GetCompletedForTest());
+  EXPECT_TRUE(title_label->font_list().GetFontStyle() &
+              gfx::Font::FontStyle::STRIKE_THROUGH);
+}
+
+TEST_F(GlanceablesTaskViewStableLaunchTest, InvokesMarkAsCompletedCallback) {
+  const auto task = api::Task("task-id", "Task title", /*completed=*/false,
+                              /*due=*/std::nullopt,
+                              /*has_subtasks=*/false, /*has_email_link=*/false,
+                              /*has_notes=*/false, /*updated=*/base::Time());
+
+  base::test::TestFuture<const std::string&, bool> future;
+
+  const auto widget = CreateFramelessTestWidget();
+  widget->SetFullscreen(true);
+  const auto* const view =
+      widget->SetContentsView(std::make_unique<GlanceablesTaskViewV2>(
+          &task, /*mark_as_completed_callback=*/future.GetRepeatingCallback(),
+          /*save_callback=*/base::DoNothing()));
+  ASSERT_TRUE(view);
+
+  EXPECT_FALSE(view->GetCompletedForTest());
+
+  const auto* const checkbox = view->GetCheckButtonForTest();
+  ASSERT_TRUE(checkbox);
+
+  // Mark as completed by pressing `checkbox`.
+  {
+    GestureTapOn(checkbox);
+    EXPECT_TRUE(view->GetCompletedForTest());
+    const auto [task_id, completed] = future.Take();
+    EXPECT_EQ(task_id, "task-id");
+    EXPECT_TRUE(completed);
+  }
+
+  // Undo / mark as not completed by pressing `checkbox` again.
+  {
+    GestureTapOn(checkbox);
+    EXPECT_FALSE(view->GetCompletedForTest());
+    const auto [task_id, completed] = future.Take();
+    EXPECT_EQ(task_id, "task-id");
+    EXPECT_FALSE(completed);
+  }
+}
+
+TEST_F(GlanceablesTaskViewStableLaunchTest, EntersAndExitsEditState) {
+  base::test::ScopedFeatureList features{
+      features::kGlanceablesTimeManagementStableLaunch};
+
+  const auto task = api::Task("task-id", "Task title", /*completed=*/false,
+                              /*due=*/std::nullopt,
+                              /*has_subtasks=*/false, /*has_email_link=*/false,
+                              /*has_notes=*/false, /*updated=*/base::Time());
+
+  const auto widget = CreateFramelessTestWidget();
+  widget->SetFullscreen(true);
+  const auto* const view =
+      widget->SetContentsView(std::make_unique<GlanceablesTaskViewV2>(
+          &task, /*mark_as_completed_callback=*/base::DoNothing(),
+          /*save_callback=*/base::DoNothing()));
+
+  {
+    const auto* const title_label =
+        views::AsViewClass<views::Label>(view->GetViewByID(
+            base::to_underlying(GlanceablesViewId::kTaskItemTitleLabel)));
+    const auto* const title_text_field =
+        views::AsViewClass<views::Textfield>(view->GetViewByID(
+            base::to_underlying(GlanceablesViewId::kTaskItemTitleTextField)));
+
+    ASSERT_TRUE(title_label);
+    ASSERT_FALSE(title_text_field);
+    EXPECT_EQ(title_label->GetText(), u"Task title");
+
+    LeftClickOn(title_label);
+  }
+
+  {
+    const auto* const title_label =
+        views::AsViewClass<views::Label>(view->GetViewByID(
+            base::to_underlying(GlanceablesViewId::kTaskItemTitleLabel)));
+    const auto* const title_text_field =
+        views::AsViewClass<views::Textfield>(view->GetViewByID(
+            base::to_underlying(GlanceablesViewId::kTaskItemTitleTextField)));
+
+    ASSERT_FALSE(title_label);
+    ASSERT_TRUE(title_text_field);
+    EXPECT_EQ(title_text_field->GetText(), u"Task title");
+
+    PressAndReleaseKey(ui::VKEY_SPACE);
+    PressAndReleaseKey(ui::VKEY_U);
+    PressAndReleaseKey(ui::VKEY_P);
+    PressAndReleaseKey(ui::VKEY_D);
+
+    PressAndReleaseKey(ui::VKEY_ESCAPE);
+  }
+
+  {
+    const auto* const title_label =
+        views::AsViewClass<views::Label>(view->GetViewByID(
+            base::to_underlying(GlanceablesViewId::kTaskItemTitleLabel)));
+    const auto* const title_text_field =
+        views::AsViewClass<views::Textfield>(view->GetViewByID(
+            base::to_underlying(GlanceablesViewId::kTaskItemTitleTextField)));
+
+    ASSERT_TRUE(title_label);
+    ASSERT_FALSE(title_text_field);
+    EXPECT_EQ(title_label->GetText(), u"Task title upd");
+  }
+}
+
+TEST_F(GlanceablesTaskViewStableLaunchTest, InvokesSaveCallbackAfterAdding) {
+  base::test::TestFuture<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=*/nullptr, /*mark_as_completed_callback=*/base::DoNothing(),
+          /*save_callback=*/future.GetRepeatingCallback()));
+  ASSERT_TRUE(view);
+
+  view->UpdateTaskTitleViewForState(
+      GlanceablesTaskViewV2::TaskTitleViewState::kEdit);
+  PressAndReleaseKey(ui::VKEY_N, ui::EF_SHIFT_DOWN);
+  PressAndReleaseKey(ui::VKEY_E);
+  PressAndReleaseKey(ui::VKEY_W);
+  PressAndReleaseKey(ui::VKEY_ESCAPE);
+
+  const auto [task_id, title, callback] = future.Take();
+  EXPECT_TRUE(task_id.empty());
+  EXPECT_EQ(title, "New");
+}
+
+TEST_F(GlanceablesTaskViewStableLaunchTest, InvokesSaveCallbackAfterEditing) {
+  const auto task = api::Task("task-id", "Task title", /*completed=*/false,
+                              /*due=*/std::nullopt,
+                              /*has_subtasks=*/false, /*has_email_link=*/false,
+                              /*has_notes=*/false, /*updated=*/base::Time());
+
+  base::test::TestFuture<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()));
+  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_ESCAPE);
+
+  const auto [task_id, title, callback] = future.Take();
+  EXPECT_EQ(task_id, "task-id");
+  EXPECT_EQ(title, "Task title upd");
+}
+
+TEST_F(GlanceablesTaskViewStableLaunchTest, SupportsEditingRightAfterAdding) {
+  base::test::TestFuture<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=*/nullptr, /*mark_as_completed_callback=*/base::DoNothing(),
+          /*save_callback=*/future.GetRepeatingCallback()));
+  ASSERT_TRUE(view);
+
+  {
+    view->UpdateTaskTitleViewForState(
+        GlanceablesTaskViewV2::TaskTitleViewState::kEdit);
+    PressAndReleaseKey(ui::VKEY_N, ui::EF_SHIFT_DOWN);
+    PressAndReleaseKey(ui::VKEY_E);
+    PressAndReleaseKey(ui::VKEY_W);
+    PressAndReleaseKey(ui::VKEY_ESCAPE);
+
+    // Verify that `task_id` is empty after adding a task.
+    auto [task_id, title, callback] = future.Take();
+    EXPECT_TRUE(task_id.empty());
+    EXPECT_EQ(title, "New");
+
+    // Simulate reply, the view should update itself with the new task id.
+    const auto created_task =
+        api::Task("task-id", "New", /*completed=*/false,
+                  /*due=*/absl::nullopt,
+                  /*has_subtasks=*/false,
+                  /*has_email_link=*/false, /*has_notes=*/false,
+                  /*updated=*/base::Time::Now());
+    std::move(callback).Run(&created_task);
+  }
+
+  {
+    view->UpdateTaskTitleViewForState(
+        GlanceablesTaskViewV2::TaskTitleViewState::kEdit);
+    PressAndReleaseKey(ui::VKEY_SPACE);
+    PressAndReleaseKey(ui::VKEY_1);
+    PressAndReleaseKey(ui::VKEY_ESCAPE);
+
+    // Verify that `task_id` equals to "task-id" after editing the same task.
+    const auto [task_id, title, callback] = future.Take();
+    EXPECT_EQ(task_id, "task-id");
+    EXPECT_EQ(title, "New 1");
+  }
+}
+
+}  // namespace ash
diff --git a/ash/glanceables/tasks/glanceables_tasks_view.cc b/ash/glanceables/tasks/glanceables_tasks_view.cc
index 4187e3f60..d5150d4 100644
--- a/ash/glanceables/tasks/glanceables_tasks_view.cc
+++ b/ash/glanceables/tasks/glanceables_tasks_view.cc
@@ -15,7 +15,7 @@
 #include "ash/glanceables/common/glanceables_view_id.h"
 #include "ash/glanceables/glanceables_controller.h"
 #include "ash/glanceables/glanceables_metrics.h"
-#include "ash/glanceables/tasks/glanceables_task_view.h"
+#include "ash/glanceables/tasks/glanceables_task_view_v2.h"
 #include "ash/public/cpp/new_window_delegate.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
@@ -75,8 +75,6 @@
       ui::ImageModel::FromVectorIcon(kGlanceablesTasksAddNewTaskIcon,
                                      cros_tokens::kFocusRingColor));
   add_new_task_button->SetImageLabelSpacing(18);
-  add_new_task_button->SetBackground(
-      views::CreateThemedSolidBackground(cros_tokens::kCrosSysSystemOnBase));
   add_new_task_button->SetBorder(
       views::CreateEmptyBorder(gfx::Insets::VH(13, 18)));
   add_new_task_button->SetEnabledTextColorIds(cros_tokens::kFocusRingColor);
@@ -101,6 +99,15 @@
                                             kInteriorGlanceableBubbleMargin))
       .SetOrientation(views::LayoutOrientation::kVertical);
 
+  // It is the parent container of GlanceablesTasksView that matches the style
+  // of GlanceableTrayChildBubble. Manually update this bubble to match the
+  // spec.
+  CHECK(layer());
+  layer()->SetRoundedCornerRadius(gfx::RoundedCornersF{16.f});
+  SetBackground(
+      views::CreateThemedSolidBackground(cros_tokens::kCrosSysSystemOnBase));
+  SetBorder(nullptr);
+
   tasks_header_view_ = AddChildView(std::make_unique<views::FlexLayoutView>());
   tasks_header_view_->SetCrossAxisAlignment(views::LayoutAlignment::kCenter);
   tasks_header_view_->SetMainAxisAlignment(views::LayoutAlignment::kStart);
@@ -122,9 +129,6 @@
 
   auto* const list_view =
       scroll_view->SetContents(std::make_unique<views::View>());
-  list_view->SetPaintToLayer();
-  list_view->layer()->SetFillsBoundsOpaquely(false);
-  list_view->layer()->SetRoundedCornerRadius(gfx::RoundedCornersF(16));
   list_view->SetLayoutManager(std::make_unique<views::BoxLayout>(
       views::BoxLayout::Orientation::kVertical,
       /*inside_border_insets=*/gfx::Insets(), kListViewBetweenChildSpacing));
@@ -151,7 +155,7 @@
                               TasksLaunchSource::kHeaderButton),
           IconButton::Type::kMedium, &kGlanceablesTasksIcon,
           IDS_GLANCEABLES_TASKS_HEADER_ICON_ACCESSIBLE_NAME));
-  header_icon->SetBackgroundColor(cros_tokens::kCrosSysBaseElevated);
+  header_icon->SetBackgroundColor(SK_ColorTRANSPARENT);
   header_icon->SetProperty(views::kMarginsKey, kHeaderIconButtonMargins);
   header_icon->SetID(
       base::to_underlying(GlanceablesViewId::kTasksBubbleHeaderIcon));
@@ -218,14 +222,14 @@
       CreateTaskView(active_task_list->id, /*task=*/nullptr),
       /*index=*/0);
   pending_new_task_->UpdateTaskTitleViewForState(
-      GlanceablesTaskView::TaskTitleViewState::kEdit);
+      GlanceablesTaskViewV2::TaskTitleViewState::kEdit);
   PreferredSizeChanged();
 }
 
-std::unique_ptr<GlanceablesTaskView> GlanceablesTasksView::CreateTaskView(
+std::unique_ptr<GlanceablesTaskViewV2> GlanceablesTasksView::CreateTaskView(
     const std::string& task_list_id,
     const api::Task* task) {
-  return std::make_unique<GlanceablesTaskView>(
+  return std::make_unique<GlanceablesTaskViewV2>(
       task,
       base::BindRepeating(&GlanceablesTasksView::MarkTaskAsCompleted,
                           base::Unretained(this), task_list_id),
diff --git a/ash/glanceables/tasks/glanceables_tasks_view.h b/ash/glanceables/tasks/glanceables_tasks_view.h
index 1dfd5aaa..0f124625 100644
--- a/ash/glanceables/tasks/glanceables_tasks_view.h
+++ b/ash/glanceables/tasks/glanceables_tasks_view.h
@@ -29,7 +29,7 @@
 class Combobox;
 class GlanceablesListFooterView;
 class GlanceablesProgressBarView;
-class GlanceablesTaskView;
+class GlanceablesTaskViewV2;
 class TasksComboboxModel;
 
 // Temporary interface to allow smooth migration from `TasksBubbleView` to
@@ -73,8 +73,8 @@
   // Handles press behavior for `add_new_task_button_`.
   void AddNewTaskButtonPressed();
 
-  // Creates a `GlanceablesTaskView` instance with bound callbacks.
-  std::unique_ptr<GlanceablesTaskView> CreateTaskView(
+  // Creates a `GlanceablesTaskViewV2` instance with bound callbacks.
+  std::unique_ptr<GlanceablesTaskViewV2> CreateTaskView(
       const std::string& task_list_id,
       const api::Task* task);
 
@@ -133,7 +133,7 @@
   // Pending new task that was added after pressing `add_new_task_button_`.
   // Used to limit the number of such views to only one and to remove the view
   // from `task_items_container_view_` if needed.
-  raw_ptr<GlanceablesTaskView> pending_new_task_ = nullptr;
+  raw_ptr<GlanceablesTaskViewV2> pending_new_task_ = nullptr;
 
   // Records the time when the bubble was about to request a task list. Used for
   // metrics.
diff --git a/ash/public/cpp/accelerators.cc b/ash/public/cpp/accelerators.cc
index c86ff3c..6925ca0 100644
--- a/ash/public/cpp/accelerators.cc
+++ b/ash/public/cpp/accelerators.cc
@@ -148,6 +148,8 @@
      AcceleratorAction::kSwitchToNextIme},
     {true, ui::VKEY_I, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN,
      AcceleratorAction::kOpenFeedbackPage},
+    {true, ui::VKEY_I, ui::EF_CONTROL_DOWN | ui::EF_COMMAND_DOWN,
+     AcceleratorAction::kOpenFeedbackPage},
     {true, ui::VKEY_Q, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN,
      AcceleratorAction::kExit},
     {true, ui::VKEY_N, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN,
diff --git a/ash/public/cpp/login_accelerators.cc b/ash/public/cpp/login_accelerators.cc
index af8004d..8ef8f29f2 100644
--- a/ash/public/cpp/login_accelerators.cc
+++ b/ash/public/cpp/login_accelerators.cc
@@ -18,6 +18,10 @@
         kShowFeedback,
         ui::VKEY_I, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN,
         true, kScopeOobe | kScopeLogin,
+    },{
+        kShowFeedback,
+        ui::VKEY_I, ui::EF_CONTROL_DOWN | ui::EF_COMMAND_DOWN,
+        true, kScopeOobe | kScopeLogin,
     }, {
         kShowResetScreen,
         ui::VKEY_R, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN,
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index 8f76be7..6b4baf3 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -2638,8 +2638,6 @@
 
   context_menu_id_ = shelf_id;
 
-  menu_owner_ = source;
-
   closing_event_time_ = base::TimeTicks();
 
   // NOTE: If you convert to HAS_MNEMONICS be sure to update menu building code.
@@ -2683,7 +2681,6 @@
 }
 
 void ShelfView::OnMenuClosed(views::View* source) {
-  menu_owner_ = nullptr;
   context_menu_id_ = ShelfID();
 
   closing_event_time_ = shelf_menu_model_adapter_->GetClosingEventTime();
diff --git a/ash/shelf/shelf_view.h b/ash/shelf/shelf_view.h
index 439807c..e44f09e 100644
--- a/ash/shelf/shelf_view.h
+++ b/ash/shelf/shelf_view.h
@@ -540,6 +540,7 @@
                          ShelfItemDelegate::AppMenuItems menu_items);
 
   // Show either a context or normal click menu of given |menu_model|.
+  // |source| is either a ShelfView or a ShelfAppButton.
   // If |context_menu| is set, the displayed menu is a context menu and not
   // a menu listing one or more running applications.
   // The |click_point| is only used for |context_menu|'s.
@@ -551,6 +552,7 @@
                 ui::MenuSourceType source_type);
 
   // Callback for MenuRunner.
+  // |source| is either a ShelfView or a ShelfAppButton.
   void OnMenuClosed(views::View* source);
 
   // Overridden from views::BoundsAnimatorObserver:
@@ -654,10 +656,6 @@
   // |dragging_| is set only if the mouse is dragged far enough.
   raw_ptr<ShelfAppButton, ExperimentalAsh> drag_view_ = nullptr;
 
-  // The view showing a context menu. This can be either a ShelfView or
-  // ShelfAppButton.
-  raw_ptr<views::View, ExperimentalAsh> menu_owner_ = nullptr;
-
   // A reference to the view used as a separator between pinned and unpinned
   // items.
   raw_ptr<views::Separator, ExperimentalAsh> separator_ = nullptr;
diff --git a/ash/system/input_device_settings/input_device_settings_controller_impl.cc b/ash/system/input_device_settings/input_device_settings_controller_impl.cc
index 8e8f5c0..cc7a099 100644
--- a/ash/system/input_device_settings/input_device_settings_controller_impl.cc
+++ b/ash/system/input_device_settings/input_device_settings_controller_impl.cc
@@ -22,6 +22,7 @@
 #include "ash/system/input_device_settings/input_device_key_alias_manager.h"
 #include "ash/system/input_device_settings/input_device_notifier.h"
 #include "ash/system/input_device_settings/input_device_settings_defaults.h"
+#include "ash/system/input_device_settings/input_device_settings_metadata.h"
 #include "ash/system/input_device_settings/input_device_settings_notification_controller.h"
 #include "ash/system/input_device_settings/input_device_settings_policy_handler.h"
 #include "ash/system/input_device_settings/input_device_settings_pref_names.h"
@@ -1432,72 +1433,12 @@
 mojom::CustomizationRestriction
 InputDeviceSettingsControllerImpl::GetMouseCustomizationRestriction(
     const ui::InputDevice& mouse) {
-  if (!features::IsPeripheralCustomizationEnabled()) {
-    return mojom::CustomizationRestriction::kAllowCustomizations;
+  const auto* metadata = GetMouseMetadata(mouse);
+  if (metadata) {
+    return metadata->customization_restriction;
   }
 
-  // If the mouse is not customizable, then the CustomizationRestriction is
-  // kDisallowCustomizations.
-  if (!IsMouseCustomizable(mouse)) {
-    return mojom::CustomizationRestriction::kDisallowCustomizations;
-  }
-
-  // If the mouse is customizable based on its vid and pid but there exists
-  // duplicate ids in the keyboard list, then the CustomizationRestriction is
-  // kDisableKeyEventRewrites to disable the key event rewrite from the mouse.
-  auto* duplicate_ids = duplicate_id_finder_->GetDuplicateDeviceIds(mouse.id);
-  CHECK(duplicate_ids);
-  for (const auto& duplicate_id : *duplicate_ids) {
-    if (keyboards_.contains(duplicate_id)) {
-      return mojom::CustomizationRestriction::kDisableKeyEventRewrites;
-    }
-  }
-
-  return mojom::CustomizationRestriction::kAllowCustomizations;
-}
-
-void InputDeviceSettingsControllerImpl::
-    ApplyCustomizationRestrictionFromKeyboard(DeviceId keyboard_id) {
-  if (!features::IsPeripheralCustomizationEnabled()) {
-    return;
-  }
-
-  bool changed_restriction = false;
-  auto* duplicate_ids =
-      duplicate_id_finder_->GetDuplicateDeviceIds(keyboard_id);
-  CHECK(duplicate_ids);
-  for (const auto& duplicate_id : *duplicate_ids) {
-    auto iter = mice_.find(duplicate_id);
-    if (iter == mice_.end()) {
-      continue;
-    }
-    auto& mouse = *iter->second;
-
-    if (mouse.customization_restriction ==
-        mojom::CustomizationRestriction::kDisableKeyEventRewrites) {
-      continue;
-    }
-
-    mouse.customization_restriction =
-        mojom::CustomizationRestriction::kDisableKeyEventRewrites;
-    changed_restriction = true;
-    InitializeMouseSettings(&mouse);
-    DispatchMouseSettingsChanged(mouse.id);
-  }
-
-  // If the restriction changed for any mouse, refresh the observing to match
-  // the new restriction.
-  if (changed_restriction) {
-    PeripheralCustomizationEventRewriter* rewriter =
-        Shell::Get()
-            ->event_rewriter_controller()
-            ->peripheral_customization_event_rewriter();
-    DeviceId id = *duplicate_ids->begin();
-    if (rewriter->mice_to_observe().contains(id)) {
-      rewriter->StopObserving();
-      StartObservingButtons(id);
-    }
-  }
+  return mojom::CustomizationRestriction::kDisableKeyEventRewrites;
 }
 
 void InputDeviceSettingsControllerImpl::OnKeyboardListUpdated(
@@ -1510,8 +1451,6 @@
     InitializeKeyboardSettings(mojom_keyboard.get());
     keyboards_.insert_or_assign(keyboard.id, std::move(mojom_keyboard));
     DispatchKeyboardConnected(keyboard.id);
-    // Update mouse restrictions if we have a keyboard with the same id.
-    ApplyCustomizationRestrictionFromKeyboard(keyboard.id);
   }
 
   for (const auto id : keyboard_ids_to_remove) {
diff --git a/ash/system/input_device_settings/input_device_settings_controller_impl.h b/ash/system/input_device_settings/input_device_settings_controller_impl.h
index e088ecec..2006bc3 100644
--- a/ash/system/input_device_settings/input_device_settings_controller_impl.h
+++ b/ash/system/input_device_settings/input_device_settings_controller_impl.h
@@ -190,19 +190,11 @@
   void RefreshCachedKeyboardSettings();
   void RefreshCachedTouchpadSettings();
 
-  // Get the mouse customization restriction. There are three different cases:
-  // 1. If the mouse is customizable and there is no duplicate ids in the
-  // keyboards, return kAllowCustomizations.
-  // 2. If the mouse is customizable but there exists
-  // duplicate ids in the keyboards, return kDisableKeyEventRewrites.
-  // 3. If the mouse is not customizable, return kDisallowCustomizations.
+  // Get the mouse customization restriction based on the mouse metadata. Return
+  // kDisableKeyEventRewrites by default if there is no mouse metadata.
   mojom::CustomizationRestriction GetMouseCustomizationRestriction(
       const ui::InputDevice& mouse);
 
-  // Update the restriction for currently connected mice once a keyboard with
-  // the same id connects to disable the key event rewrite for the mice.
-  void ApplyCustomizationRestrictionFromKeyboard(DeviceId keyboard_id);
-
   mojom::Mouse* FindMouse(DeviceId id);
   mojom::Touchpad* FindTouchpad(DeviceId id);
   mojom::Keyboard* FindKeyboard(DeviceId id);
diff --git a/ash/system/input_device_settings/input_device_settings_controller_unittest.cc b/ash/system/input_device_settings/input_device_settings_controller_unittest.cc
index cbf0c6c..9ec7f9d 100644
--- a/ash/system/input_device_settings/input_device_settings_controller_unittest.cc
+++ b/ash/system/input_device_settings/input_device_settings_controller_unittest.cc
@@ -158,8 +158,8 @@
                                                "kSampleCustomizableMouse",
                                                /*phys=*/"",
                                                /*sys_path=*/base::FilePath(),
-                                               /*vendor=*/0x0007,
-                                               /*product=*/0x0008,
+                                               /*vendor=*/0xffff,
+                                               /*product=*/0xfffe,
                                                /*version=*/0x0009);
 
 constexpr char kUserEmail1[] = "example1@abc.com";
@@ -770,45 +770,6 @@
       keyboard_pref_handler_->num_login_screen_keyboard_settings_updated(), 3u);
 }
 
-TEST_F(InputDeviceSettingsControllerTest, BlockMouseKeyEventRewrite) {
-  fake_device_manager_->AddFakeKeyboard(kSampleKeyboardInternal2,
-                                        kKbdTopRowLayout1Tag);
-  EXPECT_EQ(true, IsMouseCustomizable(kSampleCustomizableMouse));
-  fake_device_manager_->AddFakeMouse(kSampleCustomizableMouse);
-  EXPECT_EQ(mojom::CustomizationRestriction::kDisableKeyEventRewrites,
-            controller_->GetConnectedMice()[0]->customization_restriction);
-
-  fake_device_manager_->RemoveAllDevices();
-  fake_device_manager_->AddFakeMouse(kSampleCustomizableMouse);
-  EXPECT_EQ(true, IsMouseCustomizable(kSampleCustomizableMouse));
-  EXPECT_EQ(mojom::CustomizationRestriction::kAllowCustomizations,
-            controller_->GetConnectedMice()[0]->customization_restriction);
-  fake_device_manager_->AddFakeKeyboard(kSampleKeyboardInternal2,
-                                        kKbdTopRowLayout1Tag);
-  EXPECT_EQ(mojom::CustomizationRestriction::kDisableKeyEventRewrites,
-            controller_->GetConnectedMice()[0]->customization_restriction);
-}
-
-TEST_F(InputDeviceSettingsControllerTest,
-       BlockMouseKeyEventRewriteRestartObserving) {
-  fake_device_manager_->AddFakeMouse(kSampleCustomizableMouse);
-  EXPECT_EQ(mojom::CustomizationRestriction::kAllowCustomizations,
-            controller_->GetConnectedMice()[0]->customization_restriction);
-
-  controller_->StartObservingButtons(kSampleCustomizableMouse.id);
-  auto* rewriter = Shell::Get()
-                       ->event_rewriter_controller()
-                       ->peripheral_customization_event_rewriter();
-  EXPECT_EQ(1u, rewriter->mice_to_observe().size());
-
-  fake_device_manager_->AddFakeKeyboard(kSampleKeyboardInternal2,
-                                        kKbdTopRowLayout1Tag);
-  EXPECT_EQ(mojom::CustomizationRestriction::kDisableKeyEventRewrites,
-            controller_->GetConnectedMice()[0]->customization_restriction);
-
-  EXPECT_EQ(1u, rewriter->mice_to_observe().size());
-}
-
 TEST_F(InputDeviceSettingsControllerTest, KeyboardSettingsAreValid) {
   fake_device_manager_->AddFakeKeyboard(kSampleKeyboardInternal,
                                         kKbdTopRowLayout1Tag);
@@ -1356,8 +1317,9 @@
   ASSERT_EQ(0u, rewriter->graphics_tablets_to_observe().size());
 }
 
-TEST_F(InputDeviceSettingsControllerTest, ObservingUncustomizableMouseButtons) {
-  ui::DeviceDataManagerTestApi().SetMouseDevices({kSampleUncustomizableMouse});
+TEST_F(InputDeviceSettingsControllerTest, ObservingMouseButtons) {
+  ui::DeviceDataManagerTestApi().SetMouseDevices(
+      {kSampleUncustomizableMouse, kSampleCustomizableMouse});
 
   auto* rewriter = Shell::Get()
                        ->event_rewriter_controller()
@@ -1367,6 +1329,11 @@
   ASSERT_EQ(0u, rewriter->mice_to_observe().size());
   EXPECT_FALSE(
       rewriter->mice_to_observe().contains(kSampleUncustomizableMouse.id));
+
+  controller_->StartObservingButtons(kSampleCustomizableMouse.id);
+  ASSERT_EQ(1u, rewriter->mice_to_observe().size());
+  EXPECT_TRUE(
+      rewriter->mice_to_observe().contains(kSampleCustomizableMouse.id));
 }
 
 TEST_F(InputDeviceSettingsControllerTest, ObservingButtonsDuplicateIds) {
diff --git a/ash/system/input_device_settings/input_device_settings_metadata.cc b/ash/system/input_device_settings/input_device_settings_metadata.cc
index 2d3f875..a14bf16 100644
--- a/ash/system/input_device_settings/input_device_settings_metadata.cc
+++ b/ash/system/input_device_settings/input_device_settings_metadata.cc
@@ -13,12 +13,17 @@
 
 namespace {
 static constexpr auto kMouseMetadata =
-    base::MakeFixedFlatMap<VendorProductId, MouseMetadata>({
-        {{0xffff, 0xffff},
-         {mojom::CustomizationRestriction::kAllowCustomizations}},  // Fake data
-                                                                    // for
-                                                                    // testing.
-    });
+    base::MakeFixedFlatMap<VendorProductId, MouseMetadata>(
+        {// Fake data for testing.
+         {{0xffff, 0xfffe},
+          {mojom::CustomizationRestriction::kAllowCustomizations}},
+         // Fake data for testing.
+         {{0xffff, 0xffff},
+          {mojom::CustomizationRestriction::kDisallowCustomizations}},
+         // Razer Naga Pro (USB Dongle)
+         {{0x1532, 0x0090},
+          {mojom::CustomizationRestriction::
+               kAllowAlphabetOrNumberKeyEventRewrites}}});
 }
 
 bool MouseMetadata::operator==(const MouseMetadata& other) const {
diff --git a/ash/system/input_device_settings/input_device_settings_metadata_unittest.cc b/ash/system/input_device_settings/input_device_settings_metadata_unittest.cc
index 847af86..13e6b51 100644
--- a/ash/system/input_device_settings/input_device_settings_metadata_unittest.cc
+++ b/ash/system/input_device_settings/input_device_settings_metadata_unittest.cc
@@ -33,7 +33,7 @@
   const auto* metadata2 = GetMouseMetadata(kSampleMouse2);
   MouseMetadata expected_metadata;
   expected_metadata.customization_restriction =
-      mojom::CustomizationRestriction::kAllowCustomizations;
+      mojom::CustomizationRestriction::kDisallowCustomizations;
   ASSERT_TRUE(metadata2);
   EXPECT_EQ(*metadata2, expected_metadata);
 }
diff --git a/ash/system/input_device_settings/input_device_settings_utils.cc b/ash/system/input_device_settings/input_device_settings_utils.cc
index 4e3a6f0c..e0450e2 100644
--- a/ash/system/input_device_settings/input_device_settings_utils.cc
+++ b/ash/system/input_device_settings/input_device_settings_utils.cc
@@ -161,15 +161,6 @@
   return &list_value->GetList();
 }
 
-bool IsMouseCustomizable(const ui::InputDevice& device) {
-  // TODO(wangdanny): Update uncustomizable mice set with devices' vid and pid.
-  static constexpr auto kUncustomizableMice =
-      base::MakeFixedFlatSet<VendorProductId>({
-          {0xffff, 0xffff},  // Fake data for testing.
-      });
-  return !kUncustomizableMice.contains({device.vendor_id, device.product_id});
-}
-
 bool IsKeyboardPretendingToBeMouse(const ui::InputDevice& device) {
   static base::NoDestructor<base::flat_set<VendorProductId>> logged_devices;
   static constexpr auto kKeyboardsPretendingToBeMice =
diff --git a/ash/system/input_device_settings/input_device_settings_utils.h b/ash/system/input_device_settings/input_device_settings_utils.h
index 493ed12..3e8cfbf 100644
--- a/ash/system/input_device_settings/input_device_settings_utils.h
+++ b/ash/system/input_device_settings/input_device_settings_utils.h
@@ -135,9 +135,6 @@
 // Returns whether the given keyboard is ChromeOS layout keyboard.
 ASH_EXPORT bool IsChromeOSKeyboard(const mojom::Keyboard& keyboard);
 
-// This helper function checks if the mouse is customizable.
-ASH_EXPORT bool IsMouseCustomizable(const ui::InputDevice& device);
-
 }  // namespace ash
 
 #endif  // ASH_SYSTEM_INPUT_DEVICE_SETTINGS_INPUT_DEVICE_SETTINGS_UTILS_H_
diff --git a/ash/system/input_device_settings/input_device_settings_utils_unittest.cc b/ash/system/input_device_settings/input_device_settings_utils_unittest.cc
index 082d4b0..f437d0d 100644
--- a/ash/system/input_device_settings/input_device_settings_utils_unittest.cc
+++ b/ash/system/input_device_settings/input_device_settings_utils_unittest.cc
@@ -623,23 +623,4 @@
             remapping3->remapping_action->get_accelerator_action());
 }
 
-TEST(IsMouseCustomizable, IsMouseCustomizable) {
-  const ui::InputDevice kSampleUncustomizableMouse(
-      5, ui::INPUT_DEVICE_USB, "kSampleUncustomizableMouse",
-      /*phys=*/"",
-      /*sys_path=*/base::FilePath(),
-      /*vendor=*/0xffff,
-      /*product=*/0xffff,
-      /*version=*/0x0009);
-  const ui::InputDevice kSampleCustomizableMouse(4, ui::INPUT_DEVICE_USB,
-                                                 "kSampleCustomizableMouse",
-                                                 /*phys=*/"",
-                                                 /*sys_path=*/base::FilePath(),
-                                                 /*vendor=*/0x0007,
-                                                 /*product=*/0x0008,
-                                                 /*version=*/0x0009);
-  EXPECT_FALSE(IsMouseCustomizable(kSampleUncustomizableMouse));
-  EXPECT_TRUE(IsMouseCustomizable(kSampleCustomizableMouse));
-}
-
 }  // namespace ash
diff --git a/ash/system/unified/glanceable_tray_bubble.cc b/ash/system/unified/glanceable_tray_bubble.cc
index 048c0e1c..dd4998be 100644
--- a/ash/system/unified/glanceable_tray_bubble.cc
+++ b/ash/system/unified/glanceable_tray_bubble.cc
@@ -48,7 +48,6 @@
 
 views::Widget* GlanceableTrayBubble::GetBubbleWidget() const {
   return bubble_wrapper_->GetBubbleWidget();
-  ;
 }
 
 views::View* GlanceableTrayBubble::GetTasksView() {
diff --git a/ash/system/unified/glanceable_tray_bubble_view.cc b/ash/system/unified/glanceable_tray_bubble_view.cc
index 0a65199..ebb8261 100644
--- a/ash/system/unified/glanceable_tray_bubble_view.cc
+++ b/ash/system/unified/glanceable_tray_bubble_view.cc
@@ -28,10 +28,12 @@
 #include "components/session_manager/session_manager_types.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/base/models/list_model.h"
+#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
 #include "ui/compositor/layer.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/views/controls/scroll_view.h"
 #include "ui/views/focus/focus_manager.h"
+#include "ui/views/highlight_border.h"
 
 namespace ash {
 
@@ -49,6 +51,50 @@
 // For Calendar for Glanceables:
 constexpr auto kCalendarBubbleBorder = gfx::Insets::TLBR(8, 0, 0, 0);
 
+// Tasks Glanceables constants.
+constexpr int kGlanceablesContainerCornerRadius = 24;
+
+// The margin between each glanceable views.
+constexpr int kMarginBetweenGlanceables = 8;
+
+// The container view of time management glanceables, which includes Tasks and
+// Classroom.
+class TimeManagementContainer : public views::FlexLayoutView {
+ public:
+  METADATA_HEADER(TimeManagementContainer);
+  TimeManagementContainer() {
+    SetPaintToLayer();
+    layer()->SetFillsBoundsOpaquely(false);
+    SetProperty(views::kMarginsKey,
+                gfx::Insets::TLBR(0, 0, kMarginBetweenGlanceables, 0));
+    SetInteriorMargin(gfx::Insets(12));
+    SetBackground(views::CreateThemedRoundedRectBackground(
+        cros_tokens::kCrosSysSystemBaseElevated,
+        kGlanceablesContainerCornerRadius));
+    SetBorder(std::make_unique<views::HighlightBorder>(
+        kGlanceablesContainerCornerRadius,
+        views::HighlightBorder::Type::kHighlightBorderOnShadow));
+    SetDefault(views::kFlexBehaviorKey,
+               views::FlexSpecification(
+                   views::MinimumFlexSizeRule::kPreferredSnapToZero,
+                   views::MaximumFlexSizeRule::kUnbounded));
+  }
+  TimeManagementContainer(const TimeManagementContainer&) = delete;
+  TimeManagementContainer& operator=(const TimeManagementContainer&) = delete;
+  ~TimeManagementContainer() override = default;
+
+  void ChildPreferredSizeChanged(views::View* child) override {
+    PreferredSizeChanged();
+  }
+
+  void ChildVisibilityChanged(views::View* child) override {
+    PreferredSizeChanged();
+  }
+};
+
+BEGIN_METADATA(TimeManagementContainer, views::FlexLayoutView)
+END_METADATA
+
 // The view that parents glanceable bubbles. It's a flex layout view that
 // propagates child preferred size changes to the tray bubble view and the
 // container bounds changes to the bubble view.
@@ -83,14 +129,13 @@
       const views::ViewHierarchyChangedDetails& details) override {
     views::FlexLayoutView::ViewHierarchyChanged(details);
 
-    const int kDefaultMargin = 8;
     for (size_t i = 0; i < children().size(); ++i) {
       views::View* child = children()[i];
       child->SetProperty(
           views::kMarginsKey,
-          gfx::Insets::TLBR(i == 0u ? 0 : kDefaultMargin, 0,
-                            i == children().size() - 1 ? 0 : kDefaultMargin,
-                            0));
+          gfx::Insets::TLBR(
+              i == 0u ? 0 : kMarginBetweenGlanceables, 0,
+              i == children().size() - 1 ? 0 : kMarginBetweenGlanceables, 0));
     }
 
     if (details.parent == this && details.child->GetVisible()) {
@@ -223,14 +268,16 @@
   const int screen_max_height =
       CalculateMaxTrayBubbleHeight(shelf_->GetWindow());
   if (!calendar_view_) {
-    auto* calendar_parent_view = scroll_view_->contents();
     if (is_calendar_for_glanceables) {
-      calendar_parent_view =
+      calendar_container_ =
           AddChildView(std::make_unique<views::FlexLayoutView>());
-      calendar_parent_view->SetBorder(
+      calendar_container_->SetBorder(
           views::CreateEmptyBorder(kCalendarBubbleBorder));
     }
 
+    auto* calendar_parent_view = is_calendar_for_glanceables
+                                     ? calendar_container_
+                                     : scroll_view_->contents();
     calendar_view_ = calendar_parent_view->AddChildView(
         std::make_unique<CalendarView>(/*for_glanceables_container=*/true));
     SetCalendarPreferredSize();
@@ -250,16 +297,17 @@
   ChangeAnchorAlignment(shelf_->alignment());
   ChangeAnchorRect(shelf_->GetSystemTrayAnchorRect());
 
-  auto* const classroom_client =
-      Shell::Get()->glanceables_controller()->GetClassroomClient();
-  if (should_show_non_calendar_glanceables && classroom_client) {
-    if (!classroom_bubble_student_view_) {
-      classroom_client->IsStudentRoleActive(base::BindOnce(
-          &GlanceableTrayBubbleView::AddClassroomBubbleStudentViewIfNeeded,
-          weak_ptr_factory_.GetWeakPtr()));
+  if (!features::IsGlanceablesTimeManagementStableLaunchEnabled()) {
+    auto* const classroom_client =
+        Shell::Get()->glanceables_controller()->GetClassroomClient();
+    if (should_show_non_calendar_glanceables && classroom_client) {
+      if (!classroom_bubble_student_view_) {
+        classroom_client->IsStudentRoleActive(base::BindOnce(
+            &GlanceableTrayBubbleView::AddClassroomBubbleStudentViewIfNeeded,
+            weak_ptr_factory_.GetWeakPtr()));
+      }
     }
   }
-
   calendar_view_->ScrollViewToVisible();
 
   ClipScrollViewHeight(screen_max_height);
@@ -312,28 +360,7 @@
   classroom_bubble_student_view_ = scroll_contents->AddChildViewAt(
       std::make_unique<ClassroomBubbleStudentView>(), calendar_view_index);
 
-  const bool is_calendar_for_glanceables =
-      features::IsGlanceablesV2CalendarViewEnabled();
-
-  // For Calendar for Glanceables: `calendar_view_` should be focused before the
-  // `scroll_view_`. Otherwise `calendar_view_` should be focused before other
-  // bubbles inside `scroll_view_`.
-  views::View* const default_focused_child =
-      is_calendar_for_glanceables
-          ? GetChildrenFocusList().front()
-          : scroll_contents->GetChildrenFocusList().front();
-  if (default_focused_child != calendar_view_) {
-    auto* target_view =
-        is_calendar_for_glanceables ? calendar_view_->parent() : calendar_view_;
-    target_view->InsertBeforeInFocusList(default_focused_child);
-  }
-
-  // Only adds `tasks_bubble_view_` after `calendar_view_` in the focus list if
-  // `kGlanceablesCalendarView` is disabled since otherwise they are not at the
-  // same level in the view hierarchy.
-  if (!is_calendar_for_glanceables && tasks_bubble_view_) {
-    tasks_bubble_view_->InsertAfterInFocusList(calendar_view_);
-  }
+  AdjustChildrenFocusOrder();
 }
 
 void GlanceableTrayBubbleView::AddTaskBubbleViewIfNeeded(
@@ -342,39 +369,18 @@
     return;
   }
   // Add tasks bubble before everything.
-  auto* const scroll_contents = scroll_view_->contents();
-
-  std::unique_ptr<GlanceablesTasksViewBase> view;
-  if (base::FeatureList::IsEnabled(
-          features::kGlanceablesTimeManagementStableLaunch)) {
-    view = std::make_unique<GlanceablesTasksView>(task_lists);
+  if (features::IsGlanceablesTimeManagementStableLaunchEnabled()) {
+    time_management_container_view_ =
+        AddChildViewAt(std::make_unique<TimeManagementContainer>(), 0);
+    tasks_bubble_view_ = time_management_container_view_->AddChildView(
+        std::make_unique<GlanceablesTasksView>(task_lists));
+    UpdateBubble();
   } else {
-    view = std::make_unique<TasksBubbleView>(task_lists);
-  }
-  tasks_bubble_view_ = scroll_contents->AddChildViewAt(std::move(view), 0);
-
-  const bool is_calendar_for_glanceables =
-      features::IsGlanceablesV2CalendarViewEnabled();
-
-  // For Calendar for Glanceables: `calendar_view_` should be focused before the
-  // `scroll_view_`. Otherwise `calendar_view_` should be focused before other
-  // bubbles inside `scroll_view_`.
-  views::View* const default_focused_child =
-      is_calendar_for_glanceables
-          ? GetChildrenFocusList().front()
-          : scroll_contents->GetChildrenFocusList().front();
-  if (default_focused_child != calendar_view_) {
-    auto* target_view =
-        is_calendar_for_glanceables ? calendar_view_->parent() : calendar_view_;
-    target_view->InsertBeforeInFocusList(default_focused_child);
+    tasks_bubble_view_ = scroll_view_->contents()->AddChildViewAt(
+        std::make_unique<TasksBubbleView>(task_lists), 0);
   }
 
-  // Only adds `tasks_bubble_view_` after `calendar_view_` in the focus list if
-  // `kGlanceablesCalendarView` is disabled since otherwise they are not at the
-  // same level in the view hierarchy.
-  if (!is_calendar_for_glanceables) {
-    tasks_bubble_view_->InsertAfterInFocusList(calendar_view_);
-  }
+  AdjustChildrenFocusOrder();
 }
 
 void GlanceableTrayBubbleView::OnGlanceablesContainerPreferredSizeChanged() {
@@ -400,6 +406,47 @@
   }
 }
 
+void GlanceableTrayBubbleView::AdjustChildrenFocusOrder() {
+  const bool is_calendar_for_glanceables =
+      features::IsGlanceablesV2CalendarViewEnabled();
+
+  // Make sure the view that contains calendar is the first in the focus list of
+  // glanceable views. Depending on whether GlanceablesV2CalendarView is
+  // enabled, the nearest common ancestor of the calendar view and other
+  // glanceables is `this`, or `scroll_view_->contents()`.
+  if (is_calendar_for_glanceables) {
+    auto* default_focused_child = GetChildrenFocusList().front();
+    if (default_focused_child != calendar_container_) {
+      calendar_container_->InsertBeforeInFocusList(default_focused_child);
+    }
+  } else {
+    auto* default_focused_child =
+        scroll_view_->contents()->GetChildrenFocusList().front();
+    if (default_focused_child != calendar_view_) {
+      calendar_view_->InsertBeforeInFocusList(default_focused_child);
+    }
+  }
+
+  const bool time_management_stable_launch =
+      features::IsGlanceablesTimeManagementStableLaunchEnabled();
+
+  // Only adds the time management view/container after the calendar
+  // view/container in the focus list if the calendar flag and the time
+  // management flag are on or off at the same time. Otherwise one of them will
+  // be in the scroll view and the other will be at the same level of the scroll
+  // view.
+  if (is_calendar_for_glanceables != time_management_stable_launch) {
+    return;
+  }
+
+  if (time_management_stable_launch) {
+    time_management_container_view_->InsertAfterInFocusList(
+        calendar_container_);
+  } else {
+    tasks_bubble_view_->InsertAfterInFocusList(calendar_view_);
+  }
+}
+
 void GlanceableTrayBubbleView::SetCalendarPreferredSize() const {
   const bool is_calendar_for_glanceables =
       features::IsGlanceablesV2CalendarViewEnabled();
diff --git a/ash/system/unified/glanceable_tray_bubble_view.h b/ash/system/unified/glanceable_tray_bubble_view.h
index 7032554a..ec87496 100644
--- a/ash/system/unified/glanceable_tray_bubble_view.h
+++ b/ash/system/unified/glanceable_tray_bubble_view.h
@@ -66,6 +66,10 @@
   void OnGlanceablesContainerPreferredSizeChanged();
   void OnGlanceablesContainerHeightChanged(int height_delta);
 
+  // Adjusts the order of the views in the focus list under
+  // GlanceableTrayBubbleView.
+  void AdjustChildrenFocusOrder();
+
   // Sets the preferred size of `calendar_view_`. This is called during
   // initialization and when the screen height changes.
   void SetCalendarPreferredSize() const;
@@ -83,16 +87,24 @@
   // A scrollable view which contains the individual glanceables.
   raw_ptr<views::ScrollView, ExperimentalAsh> scroll_view_ = nullptr;
 
-  // Child bubble view for the tasks glanceable. Owned by bubble_view_.
+  // Container view for the tasks and classroom glanceables. Owned by this view.
+  raw_ptr<views::FlexLayoutView, ExperimentalAsh>
+      time_management_container_view_ = nullptr;
+
+  // Child bubble view for the tasks glanceable. Owned by this view.
   raw_ptr<GlanceablesTasksViewBase, ExperimentalAsh> tasks_bubble_view_ =
       nullptr;
 
   // Child bubble view for the student classrooms glanceable. Owned by
-  // bubble_view_.
+  // this view.
   raw_ptr<ClassroomBubbleStudentView, ExperimentalAsh>
       classroom_bubble_student_view_ = nullptr;
 
-  // Child bubble view for the calendar glanceable. Owned by bubble_view_.
+  // The parent container of `calendar_view_`. Only exists if the glanceables
+  // calendar flag is on.
+  raw_ptr<views::FlexLayoutView, ExperimentalAsh> calendar_container_ = nullptr;
+
+  // Child bubble view for the calendar glanceable. Owned by this view.
   raw_ptr<CalendarView, ExperimentalAsh> calendar_view_ = nullptr;
 
   base::CallbackListSubscription on_contents_scrolled_subscription_;
diff --git a/ash/webui/common/resources/BUILD.gn b/ash/webui/common/resources/BUILD.gn
index 594ac60e..fcebf76 100644
--- a/ash/webui/common/resources/BUILD.gn
+++ b/ash/webui/common/resources/BUILD.gn
@@ -162,6 +162,7 @@
   "quick_unlock/utils.ts",
   "typescript_utils/strict_query.ts",
   "quick_unlock/lock_screen_constants.ts",
+  "sea_pen/sea_pen_utils.ts",
   "shortcut_input_ui/fake_shortcut_input_provider.ts",
   "shortcut_input_ui/shortcut_utils.ts",
 ]
diff --git a/ash/webui/common/resources/sea_pen/sea_pen_utils.ts b/ash/webui/common/resources/sea_pen/sea_pen_utils.ts
new file mode 100644
index 0000000..efd6595
--- /dev/null
+++ b/ash/webui/common/resources/sea_pen/sea_pen_utils.ts
@@ -0,0 +1,25 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {FilePath} from 'chrome://resources/mojo/mojo/public/mojom/base/file_path.mojom-webui.js';
+import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js';
+
+// Returns true if `maybeDataUrl` is a Url that contains a base64 encoded image.
+export function isImageDataUrl(maybeDataUrl: unknown): maybeDataUrl is Url {
+  return !!maybeDataUrl && typeof maybeDataUrl === 'object' &&
+      'url' in maybeDataUrl && typeof maybeDataUrl.url === 'string' &&
+      (maybeDataUrl.url.startsWith('data:image/png;base64') ||
+       maybeDataUrl.url.startsWith('data:image/jpeg;base64'));
+}
+
+// Returns true if `maybeArray` is an array with at least one item.
+export function isNonEmptyArray(maybeArray: unknown): maybeArray is unknown[] {
+  return Array.isArray(maybeArray) && maybeArray.length > 0;
+}
+
+// Returns true is `obj` is a FilePath with a non-empty path.
+export function isNonEmptyFilePath(obj: unknown): obj is FilePath {
+  return !!obj && typeof obj === 'object' && 'path' in obj &&
+      typeof obj.path === 'string' && !!obj.path;
+}
diff --git a/ash/webui/personalization_app/resources/js/ambient/albums_subpage_element.ts b/ash/webui/personalization_app/resources/js/ambient/albums_subpage_element.ts
index 478569a..c58f62b 100644
--- a/ash/webui/personalization_app/resources/js/ambient/albums_subpage_element.ts
+++ b/ash/webui/personalization_app/resources/js/ambient/albums_subpage_element.ts
@@ -14,12 +14,13 @@
 import './art_album_dialog_element.js';
 import '../../css/common.css.js';
 
+import {isNonEmptyArray} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js';
 import {assert} from 'chrome://resources/js/assert.js';
 
 import {AmbientModeAlbum, TopicSource} from '../../personalization_app.mojom-webui.js';
 import {PersonalizationRouterElement} from '../personalization_router_element.js';
 import {WithPersonalizationStore} from '../personalization_store.js';
-import {getNumberOfGridItemsPerRow, getZerosArray, isNonEmptyArray} from '../utils.js';
+import {getNumberOfGridItemsPerRow} from '../utils.js';
 
 import {AlbumSelectedChangedEvent} from './album_list_element.js';
 import {getTemplate} from './albums_subpage_element.html.js';
@@ -101,7 +102,7 @@
   private getLoadingTiles_(): number[] {
     const x = getNumberOfGridItemsPerRow();
     const y = Math.floor(this.offsetHeight / kTileHeightPx);
-    return getZerosArray(x * y);
+    return new Array(x * y).fill(0);
   }
 
   private loadingAlbums_(): boolean {
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_observer.ts b/ash/webui/personalization_app/resources/js/ambient/ambient_observer.ts
index 6b0022f7..818760c 100644
--- a/ash/webui/personalization_app/resources/js/ambient/ambient_observer.ts
+++ b/ash/webui/personalization_app/resources/js/ambient/ambient_observer.ts
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {isNonEmptyArray} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js';
 import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js';
 
 import {AmbientModeAlbum, AmbientObserverInterface, AmbientObserverReceiver, AmbientProviderInterface, AmbientTheme, AmbientUiVisibility, TemperatureUnit, TopicSource} from '../../personalization_app.mojom-webui.js';
@@ -9,7 +10,7 @@
 import {logGooglePhotosPreviewsLoadTime} from '../personalization_metrics_logger.js';
 import {Paths} from '../personalization_router_element.js';
 import {PersonalizationStore} from '../personalization_store.js';
-import {isNonEmptyArray, isRecentHighlightsAlbum} from '../utils.js';
+import {isRecentHighlightsAlbum} from '../utils.js';
 
 import {setAlbumsAction, setAmbientModeEnabledAction, setAmbientThemeAction, setAmbientUiVisibilityAction, setPreviewsAction, setScreenSaverDurationAction, setTemperatureUnitAction, setTopicSourceAction} from './ambient_actions.js';
 import {getAmbientProvider} from './ambient_interface_provider.js';
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_preview_base.ts b/ash/webui/personalization_app/resources/js/ambient/ambient_preview_base.ts
index 8edaf1c..bfd11227 100644
--- a/ash/webui/personalization_app/resources/js/ambient/ambient_preview_base.ts
+++ b/ash/webui/personalization_app/resources/js/ambient/ambient_preview_base.ts
@@ -8,6 +8,7 @@
  * polymer element.
  */
 
+import {isNonEmptyArray} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js';
 import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js';
 import {PolymerElementProperties} from 'chrome://resources/polymer/v3_0/polymer/interfaces.js';
 
@@ -15,7 +16,6 @@
 import {isAmbientModeAllowed, isPersonalizationJellyEnabled} from '../load_time_booleans.js';
 import {setErrorAction} from '../personalization_actions.js';
 import {WithPersonalizationStore} from '../personalization_store.js';
-import {isNonEmptyArray} from '../utils.js';
 
 import {AmbientObserver} from './ambient_observer.js';
 import {getPhotoCount, getTopicSourceName} from './utils.js';
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_preview_large_element.ts b/ash/webui/personalization_app/resources/js/ambient/ambient_preview_large_element.ts
index 860064f9..de6b6af 100644
--- a/ash/webui/personalization_app/resources/js/ambient/ambient_preview_large_element.ts
+++ b/ash/webui/personalization_app/resources/js/ambient/ambient_preview_large_element.ts
@@ -15,13 +15,13 @@
 import '../../css/common.css.js';
 import '../../css/cros_button_style.css.js';
 
+import {isNonEmptyArray} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js';
 import {assert} from 'chrome://resources/js/assert.js';
 import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js';
 
 import {TopicSource} from '../../personalization_app.mojom-webui.js';
 import {logAmbientModeOptInUMA} from '../personalization_metrics_logger.js';
 import {Paths, PersonalizationRouterElement, ScrollableTarget} from '../personalization_router_element.js';
-import {isNonEmptyArray} from '../utils.js';
 
 import {setAmbientModeEnabled} from './ambient_controller.js';
 import {getAmbientProvider} from './ambient_interface_provider.js';
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.ts b/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.ts
index e137c484..386f5c63 100644
--- a/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.ts
+++ b/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.ts
@@ -22,7 +22,6 @@
 import {isAmbientModeAllowed, isPersonalizationJellyEnabled, isScreenSaverDurationEnabled} from '../load_time_booleans.js';
 import {Paths, ScrollableTarget} from '../personalization_router_element.js';
 import {WithPersonalizationStore} from '../personalization_store.js';
-import {getZerosArray} from '../utils.js';
 
 import {dismissTimeOfDayBanner, setAmbientModeEnabled} from './ambient_controller.js';
 import {getAmbientProvider} from './ambient_interface_provider.js';
@@ -242,7 +241,7 @@
   }
 
   private getPlaceholders_(x: number): number[] {
-    return getZerosArray(x);
+    return new Array(x).fill(0);
   }
 }
 
diff --git a/ash/webui/personalization_app/resources/js/personalization_app.ts b/ash/webui/personalization_app/resources/js/personalization_app.ts
index ad8935e..8782409a 100644
--- a/ash/webui/personalization_app/resources/js/personalization_app.ts
+++ b/ash/webui/personalization_app/resources/js/personalization_app.ts
@@ -128,7 +128,7 @@
 export {SeaPenTemplateQueryElement} from './wallpaper/sea_pen/sea_pen_template_query_element.js';
 export {setSeaPenProviderForTesting} from './wallpaper/sea_pen/sea_pen_interface_provider.js';
 export {SparklePlaceholderElement} from './wallpaper/sea_pen/sparkle_placeholder_element.js';
-export {isDefaultImage, isFilePath, isGooglePhotosPhoto, isWallpaperImage} from './wallpaper/utils.js';
+export {isDefaultImage, isGooglePhotosPhoto, isWallpaperImage} from './wallpaper/utils.js';
 export * from './wallpaper/wallpaper_actions.js';
 export {WallpaperCollectionsElement} from './wallpaper/wallpaper_collections_element.js';
 export {selectGooglePhotosAlbum, cancelPreviewWallpaper, confirmPreviewWallpaper, fetchCollections, fetchGooglePhotosAlbum, fetchGooglePhotosAlbums, fetchGooglePhotosPhotos, fetchGooglePhotosSharedAlbums, fetchLocalData, getDefaultImageThumbnail, getLocalImages, initializeBackdropData, fetchGooglePhotosEnabled, selectWallpaper, setCurrentWallpaperLayout, setDailyRefreshCollectionId, updateDailyRefreshWallpaper} from './wallpaper/wallpaper_controller.js';
diff --git a/ash/webui/personalization_app/resources/js/personalization_breadcrumb_element.ts b/ash/webui/personalization_app/resources/js/personalization_breadcrumb_element.ts
index 1aeba75..61901a11 100644
--- a/ash/webui/personalization_app/resources/js/personalization_breadcrumb_element.ts
+++ b/ash/webui/personalization_app/resources/js/personalization_breadcrumb_element.ts
@@ -19,6 +19,7 @@
 import '../css/cros_button_style.css.js';
 
 import {assert} from 'chrome://resources/ash/common/assert.js';
+import {isNonEmptyArray} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js';
 import {AnchorAlignment} from 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js';
 import {IronA11yKeysElement} from 'chrome://resources/polymer/v3_0/iron-a11y-keys/iron-a11y-keys.js';
 import {IronSelectorElement} from 'chrome://resources/polymer/v3_0/iron-selector/iron-selector.js';
@@ -28,7 +29,7 @@
 import {getTemplate} from './personalization_breadcrumb_element.html.js';
 import {isPathValid, Paths, PersonalizationRouterElement} from './personalization_router_element.js';
 import {WithPersonalizationStore} from './personalization_store.js';
-import {inBetween, isNonEmptyArray} from './utils.js';
+import {inBetween} from './utils.js';
 import {getSeaPenTemplates, SeaPenTemplate} from './wallpaper/sea_pen/constants.js';
 import {isSeaPenEnabled} from './wallpaper/sea_pen/load_time_booleans.js';
 import {findAlbumById} from './wallpaper/utils.js';
diff --git a/ash/webui/personalization_app/resources/js/personalization_reducers.ts b/ash/webui/personalization_app/resources/js/personalization_reducers.ts
index d33732e3..3d6ef03c 100644
--- a/ash/webui/personalization_app/resources/js/personalization_reducers.ts
+++ b/ash/webui/personalization_app/resources/js/personalization_reducers.ts
@@ -7,6 +7,7 @@
  * pure function that returns a new state object if anything has changed.
  * @see [redux tutorial]{@link https://redux.js.org/tutorials/fundamentals/part-3-state-actions-reducers}
  */
+import {isNonEmptyArray} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
 
 import {ambientReducers} from './ambient/ambient_reducers.js';
@@ -19,7 +20,6 @@
 import {ThemeState} from './theme/theme_state.js';
 import {userReducers} from './user/user_reducers.js';
 import {UserState} from './user/user_state.js';
-import {isNonEmptyArray} from './utils.js';
 import {WallpaperActionName} from './wallpaper/wallpaper_actions.js';
 import {wallpaperReducers} from './wallpaper/wallpaper_reducers.js';
 import {WallpaperState} from './wallpaper/wallpaper_state.js';
diff --git a/ash/webui/personalization_app/resources/js/personalization_test_api.ts b/ash/webui/personalization_app/resources/js/personalization_test_api.ts
index 5d1bbe9..1e70af1 100644
--- a/ash/webui/personalization_app/resources/js/personalization_test_api.ts
+++ b/ash/webui/personalization_app/resources/js/personalization_test_api.ts
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {isNonEmptyArray} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js';
 import {assert} from 'chrome://resources/js/assert.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
 
@@ -10,7 +11,6 @@
 import {PersonalizationStore} from './personalization_store.js';
 import {getThemeProvider} from './theme/theme_interface_provider.js';
 import {DEFAULT_COLOR_SCHEME} from './theme/utils.js';
-import {isNonEmptyArray} from './utils.js';
 import {setFullscreenEnabledAction} from './wallpaper/wallpaper_actions.js';
 import {selectGooglePhotosAlbum, selectWallpaper, setDailyRefreshCollectionId} from './wallpaper/wallpaper_controller.js';
 import {getWallpaperProvider} from './wallpaper/wallpaper_interface_provider.js';
diff --git a/ash/webui/personalization_app/resources/js/user/avatar_list_element.ts b/ash/webui/personalization_app/resources/js/user/avatar_list_element.ts
index 7fe759c..7d841ce9 100644
--- a/ash/webui/personalization_app/resources/js/user/avatar_list_element.ts
+++ b/ash/webui/personalization_app/resources/js/user/avatar_list_element.ts
@@ -7,6 +7,7 @@
  * that the user can select from.
  */
 
+import {isNonEmptyArray} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js';
 import {assert} from 'chrome://resources/js/assert.js';
 import {mojoString16ToString} from 'chrome://resources/js/mojo_type_util.js';
 import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js';
@@ -15,7 +16,7 @@
 import {isUserAvatarCustomizationSelectorsEnabled} from '../load_time_booleans.js';
 import {setErrorAction} from '../personalization_actions.js';
 import {WithPersonalizationStore} from '../personalization_store.js';
-import {getCheckmarkIcon, isNonEmptyArray, isSelectionEvent} from '../utils.js';
+import {getCheckmarkIcon, isSelectionEvent} from '../utils.js';
 
 import {AvatarCameraElement, AvatarCameraMode} from './avatar_camera_element.js';
 import {getTemplate} from './avatar_list_element.html.js';
diff --git a/ash/webui/personalization_app/resources/js/user/user_preview_element.ts b/ash/webui/personalization_app/resources/js/user/user_preview_element.ts
index 74c46603..f201e3a 100644
--- a/ash/webui/personalization_app/resources/js/user/user_preview_element.ts
+++ b/ash/webui/personalization_app/resources/js/user/user_preview_element.ts
@@ -10,6 +10,7 @@
 import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
 import 'chrome://resources/polymer/v3_0/paper-ripple/paper-ripple.js';
 
+import {isNonEmptyArray} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js';
 import {assert} from 'chrome://resources/js/assert.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
 import {mojoString16ToString} from 'chrome://resources/js/mojo_type_util.js';
@@ -20,7 +21,7 @@
 import {isPersonalizationJellyEnabled} from '../load_time_booleans.js';
 import {Paths, PersonalizationRouterElement} from '../personalization_router_element.js';
 import {WithPersonalizationStore} from '../personalization_store.js';
-import {isNonEmptyArray, isNonEmptyString} from '../utils.js';
+import {isNonEmptyString} from '../utils.js';
 
 import {initializeUserData} from './user_controller.js';
 import {UserImageObserver} from './user_image_observer.js';
diff --git a/ash/webui/personalization_app/resources/js/utils.ts b/ash/webui/personalization_app/resources/js/utils.ts
index 8672cff..427c8e5 100644
--- a/ash/webui/personalization_app/resources/js/utils.ts
+++ b/ash/webui/personalization_app/resources/js/utils.ts
@@ -7,7 +7,6 @@
  */
 
 import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
-import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js';
 
 import {AmbientModeAlbum, BacklightColor, BLUE_COLOR, GooglePhotosAlbum, GREEN_COLOR, INDIGO_COLOR, PURPLE_COLOR, RED_COLOR, WHITE_COLOR, YELLOW_COLOR} from './../personalization_app.mojom-webui.js';
 import {isPersonalizationJellyEnabled} from './load_time_booleans.js';
@@ -68,13 +67,6 @@
 }
 
 /**
- * Checks if argument is an array with non-zero length.
- */
-export function isNonEmptyArray(maybeArray: unknown): maybeArray is unknown[] {
-  return Array.isArray(maybeArray) && maybeArray.length > 0;
-}
-
-/**
  * Checks if argument is a string with non-zero length.
  */
 export function isNonEmptyString(maybeString: unknown): maybeString is string {
@@ -89,13 +81,6 @@
   return minVal <= num && num <= maxVal;
 }
 
-export function isImageDataUrl(maybeDataUrl: Url|null|
-                               undefined): maybeDataUrl is Url {
-  return !!maybeDataUrl && typeof maybeDataUrl.url === 'string' &&
-      (maybeDataUrl.url.startsWith('data:image/png;base64') ||
-       maybeDataUrl.url.startsWith('data:image/jpeg;base64'));
-}
-
 /** Returns the RGB hex in #ffffff format. */
 export function convertToRgbHexStr(hexVal: number): string {
   const PADDING_LENGTH = 6;
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/google_photos_albums_element.ts b/ash/webui/personalization_app/resources/js/wallpaper/google_photos_albums_element.ts
index 299128d1..97d58fd 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/google_photos_albums_element.ts
+++ b/ash/webui/personalization_app/resources/js/wallpaper/google_photos_albums_element.ts
@@ -11,6 +11,7 @@
 import '../../css/wallpaper.css.js';
 import '../../css/common.css.js';
 
+import {isNonEmptyArray} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js';
 import {assert} from 'chrome://resources/js/assert.js';
 import {IronListElement} from 'chrome://resources/polymer/v3_0/iron-list/iron-list.js';
 import {IronScrollThresholdElement} from 'chrome://resources/polymer/v3_0/iron-scroll-threshold/iron-scroll-threshold.js';
@@ -22,7 +23,7 @@
 import {PersonalizationRouterElement} from '../personalization_router_element.js';
 import {PersonalizationStateError} from '../personalization_state.js';
 import {WithPersonalizationStore} from '../personalization_store.js';
-import {getCountText, isNonEmptyArray, isRecentHighlightsAlbum} from '../utils.js';
+import {getCountText, isRecentHighlightsAlbum} from '../utils.js';
 
 import {getTemplate} from './google_photos_albums_element.html.js';
 import {getLoadingPlaceholders} from './utils.js';
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/google_photos_collection_element.ts b/ash/webui/personalization_app/resources/js/wallpaper/google_photos_collection_element.ts
index 782ffa7a..7662bd0 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/google_photos_collection_element.ts
+++ b/ash/webui/personalization_app/resources/js/wallpaper/google_photos_collection_element.ts
@@ -12,6 +12,7 @@
 import '../../css/common.css.js';
 import './google_photos_zero_state_element.js';
 
+import {isNonEmptyArray} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js';
 import {assertNotReached} from 'chrome://resources/js/assert.js';
 import {afterNextRender} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
@@ -19,7 +20,6 @@
 import {isGooglePhotosSharedAlbumsEnabled} from '../load_time_booleans.js';
 import {Paths, PersonalizationRouterElement} from '../personalization_router_element.js';
 import {WithPersonalizationStore} from '../personalization_store.js';
-import {isNonEmptyArray} from '../utils.js';
 
 import {getTemplate} from './google_photos_collection_element.html.js';
 import {fetchGooglePhotosAlbums, fetchGooglePhotosPhotos, fetchGooglePhotosSharedAlbums} from './wallpaper_controller.js';
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/google_photos_photos_element.ts b/ash/webui/personalization_app/resources/js/wallpaper/google_photos_photos_element.ts
index 9d907194..2f741b7 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/google_photos_photos_element.ts
+++ b/ash/webui/personalization_app/resources/js/wallpaper/google_photos_photos_element.ts
@@ -11,6 +11,7 @@
 import '../../css/wallpaper.css.js';
 import '../../css/common.css.js';
 
+import {isNonEmptyArray} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js';
 import {assert} from 'chrome://resources/js/assert.js';
 import {mojoString16ToString} from 'chrome://resources/js/mojo_type_util.js';
 import {IronListElement} from 'chrome://resources/polymer/v3_0/iron-list/iron-list.js';
@@ -21,7 +22,7 @@
 import {dismissErrorAction, setErrorAction} from '../personalization_actions.js';
 import {PersonalizationStateError} from '../personalization_state.js';
 import {WithPersonalizationStore} from '../personalization_store.js';
-import {getNumberOfGridItemsPerRow, isNonEmptyArray} from '../utils.js';
+import {getNumberOfGridItemsPerRow} from '../utils.js';
 
 import {DisplayableImage} from './constants.js';
 import {recordWallpaperGooglePhotosSourceUMA, WallpaperGooglePhotosSource} from './google_photos_metrics_logger.js';
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/local_images_element.ts b/ash/webui/personalization_app/resources/js/wallpaper/local_images_element.ts
index e747578..f2be506 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/local_images_element.ts
+++ b/ash/webui/personalization_app/resources/js/wallpaper/local_images_element.ts
@@ -15,6 +15,7 @@
 import '../../common/icons.html.js';
 import '../../css/common.css.js';
 
+import {isImageDataUrl, isNonEmptyFilePath} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js';
 import {assert} from 'chrome://resources/js/assert.js';
 import {FilePath} from 'chrome://resources/mojo/mojo/public/mojom/base/file_path.mojom-webui.js';
 import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js';
@@ -22,11 +23,10 @@
 
 import {CurrentWallpaper, WallpaperProviderInterface, WallpaperType} from '../../personalization_app.mojom-webui.js';
 import {WithPersonalizationStore} from '../personalization_store.js';
-import {isImageDataUrl} from '../utils.js';
 
 import {DefaultImageSymbol, DisplayableImage, kDefaultImageSymbol} from './constants.js';
 import {getTemplate} from './local_images_element.html.js';
-import {getPathOrSymbol, isDefaultImage, isFilePath} from './utils.js';
+import {getPathOrSymbol, isDefaultImage} from './utils.js';
 import {selectWallpaper} from './wallpaper_controller.js';
 import {WallpaperGridItemSelectedEvent} from './wallpaper_grid_item_element.js';
 import {getWallpaperProvider} from './wallpaper_interface_provider.js';
@@ -154,7 +154,8 @@
            currentSelected.type === WallpaperType.kDefault));
     }
     return (
-        isFilePath(pendingSelected) && image.path === pendingSelected.path ||
+        isNonEmptyFilePath(pendingSelected) &&
+            image.path === pendingSelected.path ||
         !!currentSelected && image.path === currentSelected.key &&
             !pendingSelected);
   }
@@ -168,7 +169,7 @@
     if (isDefaultImage(image)) {
       return this.i18n('defaultWallpaper');
     }
-    if (!isFilePath(image)) {
+    if (!isNonEmptyFilePath(image)) {
       return '';
     }
     const path = image.path;
@@ -207,14 +208,14 @@
     if (!image) {
       return '';
     }
-    return isFilePath(image) ? image.path : image.toString();
+    return isNonEmptyFilePath(image) ? image.path : image.toString();
   }
 
   private onImageSelected_(event: WallpaperGridItemSelectedEvent&
                            {model: {item: FilePath | DefaultImageSymbol}}) {
     assert(
         event.model.item === kDefaultImageSymbol ||
-            isFilePath(event.model.item),
+            isNonEmptyFilePath(event.model.item),
         'local image is a file path or default image');
     selectWallpaper(event.model.item, this.wallpaperProvider_, this.getStore());
   }
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/sea_pen/sea_pen_controller.ts b/ash/webui/personalization_app/resources/js/wallpaper/sea_pen/sea_pen_controller.ts
index d9e3733..561cd017 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/sea_pen/sea_pen_controller.ts
+++ b/ash/webui/personalization_app/resources/js/wallpaper/sea_pen/sea_pen_controller.ts
@@ -2,11 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {isNonEmptyArray, isNonEmptyFilePath} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js';
 import {FilePath} from 'chrome://resources/mojo/mojo/public/mojom/base/file_path.mojom-webui.js';
 
 import {SeaPenProviderInterface, SeaPenQuery, SeaPenThumbnail} from '../../../sea_pen.mojom-webui.js';
-import {isNonEmptyArray} from '../../utils.js';
-import {isFilePath} from '../utils.js';
 
 import * as seaPenAction from './sea_pen_actions.js';
 import {SeaPenStoreInterface} from './sea_pen_store.js';
@@ -15,7 +14,7 @@
     image: FilePath, provider: SeaPenProviderInterface,
     store: SeaPenStoreInterface): Promise<void> {
   // Returns if the selected image is the current wallpaper.
-  if (isFilePath(image) && image.path === store.data.currentSelected) {
+  if (isNonEmptyFilePath(image) && image.path === store.data.currentSelected) {
     return;
   }
   // Batch these changes together to reduce polymer churn as multiple state
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/sea_pen/sea_pen_images_element.ts b/ash/webui/personalization_app/resources/js/wallpaper/sea_pen/sea_pen_images_element.ts
index ee2d7aa..940b255 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/sea_pen/sea_pen_images_element.ts
+++ b/ash/webui/personalization_app/resources/js/wallpaper/sea_pen/sea_pen_images_element.ts
@@ -14,8 +14,9 @@
 import './sparkle_placeholder_element.js';
 import '../../../css/sea_pen.css.js';
 
+import {isNonEmptyArray} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js';
+
 import {SeaPenThumbnail} from '../../../sea_pen.mojom-webui.js';
-import {getZerosArray, isNonEmptyArray} from '../../utils.js';
 
 import {selectSeaPenWallpaper} from './sea_pen_controller.js';
 import {getTemplate} from './sea_pen_images_element.html.js';
@@ -78,7 +79,7 @@
   }
 
   private getPlaceholders_(x: number) {
-    return getZerosArray(x);
+    return new Array(x).fill(0);
   }
 
   private onThumbnailSelected_(event: Event&{model: {item: SeaPenThumbnail}}) {
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/sea_pen/sea_pen_recent_wallpapers_element.ts b/ash/webui/personalization_app/resources/js/wallpaper/sea_pen/sea_pen_recent_wallpapers_element.ts
index 4039085..33178ae90 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/sea_pen/sea_pen_recent_wallpapers_element.ts
+++ b/ash/webui/personalization_app/resources/js/wallpaper/sea_pen/sea_pen_recent_wallpapers_element.ts
@@ -12,13 +12,12 @@
 import '../../../css/wallpaper.css.js';
 import '../../../css/sea_pen.css.js';
 
+import {isImageDataUrl, isNonEmptyArray, isNonEmptyFilePath} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js';
 import {AnchorAlignment} from 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js';
 import {assert} from 'chrome://resources/js/assert.js';
 import {FilePath} from 'chrome://resources/mojo/mojo/public/mojom/base/file_path.mojom-webui.js';
 import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js';
 
-import {isImageDataUrl, isNonEmptyArray} from '../../utils.js';
-import {isFilePath} from '../utils.js';
 import {WallpaperGridItemSelectedEvent} from '../wallpaper_grid_item_element.js';
 
 import {RecentSeaPenData} from './constants.js';
@@ -103,8 +102,7 @@
    */
   private onRecentImagesChanged_(recentImages: FilePath[]|null) {
     this.recentImagesToDisplay_ = (recentImages || []).filter(image => {
-      if (isFilePath(image) &&
-          this.recentImageDataLoading_[image.path] === false) {
+      if (this.recentImageDataLoading_[image.path] === false) {
         const data = this.recentImageData_[image.path];
         return data && data.queryInfo && data.url;
       }
@@ -182,13 +180,13 @@
   }
 
   private isRecentImageSelected_(
-      image: FilePath, currentSelected: string|null,
+      image: FilePath|null, currentSelected: string|null,
       pendingSelected: FilePath|null) {
-    if (!isFilePath(image)) {
+    if (!isNonEmptyFilePath(image)) {
       return false;
     }
 
-    return (isFilePath(pendingSelected) &&
+    return (isNonEmptyFilePath(pendingSelected) &&
             image.path === pendingSelected.path) ||
         (!pendingSelected && image.path === currentSelected);
   }
@@ -196,7 +194,8 @@
   private onRecentImageSelected_(event: WallpaperGridItemSelectedEvent&
                                  {model: {image: FilePath}}) {
     assert(
-        isFilePath(event.model.image), 'recent Sea Pen image is a file path');
+        isNonEmptyFilePath(event.model.image),
+        'recent Sea Pen image is a file path');
     selectRecentSeaPenImage(
         event.model.image, getSeaPenProvider(), this.getStore());
   }
@@ -230,7 +229,8 @@
     // TODO (b/315069374): confirm if currently set Sea Pen wallpaper can be
     // removed.
     assert(
-        isFilePath(event.model.image), 'selected Sea Pen image is a file path');
+        isNonEmptyFilePath(event.model.image),
+        'selected Sea Pen image is a file path');
     deleteRecentSeaPenImage(
         event.model.image, getSeaPenProvider(), this.getStore());
     this.closeAllActionMenus_();
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/sea_pen/sea_pen_template_query_element.ts b/ash/webui/personalization_app/resources/js/wallpaper/sea_pen/sea_pen_template_query_element.ts
index f0a8da5..2f95284 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/sea_pen/sea_pen_template_query_element.ts
+++ b/ash/webui/personalization_app/resources/js/wallpaper/sea_pen/sea_pen_template_query_element.ts
@@ -9,11 +9,11 @@
 
 import '../../../common/icons.html.js';
 
+import {isNonEmptyArray} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js';
 import {assert} from 'chrome://resources/js/assert.js';
 
 import {SeaPenQuery, SeaPenTemplateChip, SeaPenTemplateId, SeaPenTemplateOption} from '../../../sea_pen.mojom-webui.js';
 import {Paths, PersonalizationRouterElement} from '../../personalization_router_element.js';
-import {isNonEmptyArray} from '../../utils.js';
 
 import {getSeaPenTemplates, parseTemplateText, SeaPenOption, SeaPenTemplate} from './constants.js';
 import {searchSeaPenThumbnails} from './sea_pen_controller.js';
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/utils.ts b/ash/webui/personalization_app/resources/js/wallpaper/utils.ts
index dd5f930..6150d3d 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/utils.ts
+++ b/ash/webui/personalization_app/resources/js/wallpaper/utils.ts
@@ -4,12 +4,13 @@
 
 /** @fileoverview Wallpaper related utility functions in personalization app */
 
+import {isNonEmptyArray, isNonEmptyFilePath} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js';
 import {assert} from 'chrome://resources/js/assert.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
 import {FilePath} from 'chrome://resources/mojo/mojo/public/mojom/base/file_path.mojom-webui.js';
 
 import {CurrentAttribution, CurrentWallpaper, GooglePhotosAlbum, GooglePhotosPhoto, WallpaperImage, WallpaperLayout, WallpaperType} from '../../personalization_app.mojom-webui.js';
-import {getNumberOfGridItemsPerRow, isNonEmptyArray, isNonEmptyString} from '../utils.js';
+import {getNumberOfGridItemsPerRow, isNonEmptyString} from '../utils.js';
 
 import {DefaultImageSymbol, DisplayableImage, kDefaultImageSymbol} from './constants.js';
 import {DailyRefreshState} from './wallpaper_state.js';
@@ -18,10 +19,6 @@
   return !!obj && typeof obj.unitId === 'bigint';
 }
 
-export function isFilePath(obj: any): obj is FilePath {
-  return !!obj && typeof obj.path === 'string' && obj.path;
-}
-
 export function isDefaultImage(obj: any): obj is DefaultImageSymbol {
   return obj === kDefaultImageSymbol;
 }
@@ -40,7 +37,7 @@
   if (isDefaultImage(image)) {
     return key === kDefaultImageSymbol;
   }
-  if (isFilePath(image)) {
+  if (isNonEmptyFilePath(image)) {
     return key === image.path;
   }
   assert(isGooglePhotosPhoto(image));
@@ -72,7 +69,7 @@
  */
 export function getPathOrSymbol(image: FilePath|DefaultImageSymbol): string|
     DefaultImageSymbol {
-  if (isFilePath(image)) {
+  if (isNonEmptyFilePath(image)) {
     return image.path;
   }
   assert(image === kDefaultImageSymbol, 'only one symbol should be present');
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_collections_element.ts b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_collections_element.ts
index cd787ba9..dbdcf4c3 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_collections_element.ts
+++ b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_collections_element.ts
@@ -14,6 +14,7 @@
 import '../../common/icons.html.js';
 import '../../css/common.css.js';
 
+import {isImageDataUrl, isNonEmptyArray} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js';
 import {assert} from 'chrome://resources/js/assert.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
 import {FilePath} from 'chrome://resources/mojo/mojo/public/mojom/base/file_path.mojom-webui.js';
@@ -25,7 +26,7 @@
 import {isGooglePhotosIntegrationEnabled, isPersonalizationJellyEnabled, isTimeOfDayWallpaperEnabled} from '../load_time_booleans.js';
 import {Paths, PersonalizationRouterElement} from '../personalization_router_element.js';
 import {WithPersonalizationStore} from '../personalization_store.js';
-import {getCountText, isImageDataUrl, isNonEmptyArray, isSelectionEvent} from '../utils.js';
+import {getCountText, isSelectionEvent} from '../utils.js';
 
 import {DefaultImageSymbol, kDefaultImageSymbol, kMaximumLocalImagePreviews} from './constants.js';
 import {isSeaPenEnabled} from './sea_pen/load_time_booleans.js';
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_controller.ts b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_controller.ts
index 5e6cb62..5a5927c 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_controller.ts
+++ b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_controller.ts
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {isNonEmptyArray, isNonEmptyFilePath} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js';
 import {assert} from 'chrome://resources/js/assert.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
 import {FilePath} from 'chrome://resources/mojo/mojo/public/mojom/base/file_path.mojom-webui.js';
@@ -10,10 +11,9 @@
 import {CurrentWallpaper, GooglePhotosAlbum, GooglePhotosEnablementState, GooglePhotosPhoto, WallpaperCollection, WallpaperImage, WallpaperLayout, WallpaperProviderInterface, WallpaperType} from '../../personalization_app.mojom-webui.js';
 import {setErrorAction} from '../personalization_actions.js';
 import {PersonalizationStore} from '../personalization_store.js';
-import {isNonEmptyArray} from '../utils.js';
 
 import {DisplayableImage} from './constants.js';
-import {isDefaultImage, isFilePath, isGooglePhotosPhoto, isImageAMatchForKey, isImageEqualToSelected, isWallpaperImage} from './utils.js';
+import {isDefaultImage, isGooglePhotosPhoto, isImageAMatchForKey, isImageEqualToSelected, isWallpaperImage} from './utils.js';
 import * as action from './wallpaper_actions.js';
 import {DailyRefreshType} from './wallpaper_state.js';
 
@@ -361,7 +361,7 @@
           image.unitId, /*preview_mode=*/ shouldPreview);
     } else if (isDefaultImage(image)) {
       return provider.selectDefaultImage();
-    } else if (isFilePath(image)) {
+    } else if (isNonEmptyFilePath(image)) {
       return provider.selectLocalImage(
           image, layout, /*preview_mode=*/ shouldPreview);
     } else if (isGooglePhotosPhoto(image)) {
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_fullscreen_element.ts b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_fullscreen_element.ts
index 7d09a9a..cbf77ed 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_fullscreen_element.ts
+++ b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_fullscreen_element.ts
@@ -11,13 +11,14 @@
 import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
 import '../../common/icons.html.js';
 
+import {isNonEmptyFilePath} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js';
 import {assert} from 'chrome://resources/js/assert.js';
 
 import {CurrentWallpaper, WallpaperLayout} from '../../personalization_app.mojom-webui.js';
 import {WithPersonalizationStore} from '../personalization_store.js';
 
 import {DisplayableImage} from './constants.js';
-import {getWallpaperLayoutEnum, isFilePath, isGooglePhotosPhoto} from './utils.js';
+import {getWallpaperLayoutEnum, isGooglePhotosPhoto} from './utils.js';
 import {setFullscreenEnabledAction} from './wallpaper_actions.js';
 import {cancelPreviewWallpaper, confirmPreviewWallpaper, selectWallpaper} from './wallpaper_controller.js';
 import {getTemplate} from './wallpaper_fullscreen_element.html.js';
@@ -92,7 +93,7 @@
     this.watch<WallpaperFullscreenElement['showLayoutOptions_']>(
         'showLayoutOptions_',
         state => !!state.wallpaper.pendingSelected &&
-            (isFilePath(state.wallpaper.pendingSelected) ||
+            (isNonEmptyFilePath(state.wallpaper.pendingSelected) ||
              isGooglePhotosPhoto(state.wallpaper.pendingSelected)));
     this.watch<WallpaperFullscreenElement['currentSelected_']>(
         'currentSelected_', state => state.wallpaper.currentSelected);
@@ -165,7 +166,7 @@
 
   private async onClickLayout_(event: MouseEvent) {
     assert(
-        isFilePath(this.pendingSelected_) ||
+        isNonEmptyFilePath(this.pendingSelected_) ||
             isGooglePhotosPhoto(this.pendingSelected_),
         'pendingSelected must be a local image or a Google Photos image to set layout');
     const layout = getWallpaperLayoutEnum(
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_images_element.ts b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_images_element.ts
index d5423e0..75ec042 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_images_element.ts
+++ b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_images_element.ts
@@ -12,6 +12,7 @@
 import 'chrome://resources/polymer/v3_0/iron-media-query/iron-media-query.js';
 import '../../css/wallpaper.css.js';
 
+import {isNonEmptyArray} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js';
 import {assert} from 'chrome://resources/js/assert.js';
 
 import {CurrentWallpaper, OnlineImageType, WallpaperCollection, WallpaperImage, WallpaperType} from '../../personalization_app.mojom-webui.js';
@@ -22,7 +23,6 @@
 import {setColorModeAutoSchedule} from '../theme/theme_controller.js';
 import {getThemeProvider} from '../theme/theme_interface_provider.js';
 import {ThemeObserver} from '../theme/theme_observer.js';
-import {isNonEmptyArray} from '../utils.js';
 
 import {ImageTile} from './constants.js';
 import {getLoadingPlaceholderAnimationDelay, getLoadingPlaceholders, isWallpaperImage} from './utils.js';
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_reducers.ts b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_reducers.ts
index 638ccb8..ebe6a2d 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_reducers.ts
+++ b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_reducers.ts
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {isImageDataUrl, isNonEmptyArray, isNonEmptyFilePath} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js';
 import {assert} from 'chrome://resources/js/assert.js';
 import {FilePath} from 'chrome://resources/mojo/mojo/public/mojom/base/file_path.mojom-webui.js';
 
@@ -9,13 +10,12 @@
 import {Actions} from '../personalization_actions.js';
 import {ReducerFunction} from '../personalization_reducers.js';
 import {PersonalizationState} from '../personalization_state.js';
-import {isImageDataUrl, isNonEmptyArray} from '../utils.js';
 
 import {DefaultImageSymbol, kDefaultImageSymbol} from './constants.js';
 import {SeaPenActionName, SeaPenActions} from './sea_pen/sea_pen_actions.js';
 import {seaPenReducer} from './sea_pen/sea_pen_reducer.js';
 import {SeaPenState} from './sea_pen/sea_pen_state';
-import {findAlbumById, isDefaultImage, isFilePath, isImageEqualToSelected} from './utils.js';
+import {findAlbumById, isDefaultImage, isImageEqualToSelected} from './utils.js';
 import {WallpaperActionName} from './wallpaper_actions.js';
 import {DailyRefreshType, WallpaperState} from './wallpaper_state.js';
 
@@ -121,7 +121,7 @@
         local: {
           data: imagesToKeep.reduce(
               (result, next) => {
-                const path = isFilePath(next) ? next.path : next;
+                const path = isNonEmptyFilePath(next) ? next.path : next;
                 if (state.local.data.hasOwnProperty(path)) {
                   result[path] = state.local.data[path];
                 }
@@ -269,7 +269,7 @@
         return {
           images: [
             kDefaultImageSymbol,
-            ...(state.images || []).filter(img => isFilePath(img)),
+            ...(state.images || []).filter(img => isNonEmptyFilePath(img)),
           ],
           data: {
             ...state.data,
@@ -279,7 +279,7 @@
       }
       return {
         images: Array.isArray(state.images) ?
-            state.images.filter(img => isFilePath(img)) :
+            state.images.filter(img => isNonEmptyFilePath(img)) :
             null,
         data: {...state.data, [kDefaultImageSymbol]: {url: ''}},
       };
@@ -305,7 +305,7 @@
         // Only keep image thumbnails if the image is still in |images|.
         data: newImages.reduce(
             (result, next) => {
-              const key = isFilePath(next) ? next.path : next;
+              const key = isNonEmptyFilePath(next) ? next.path : next;
               if (state.data.hasOwnProperty(key)) {
                 result[key] = state.data[key];
               }
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_selected_element.ts b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_selected_element.ts
index 01eba9c6..555354ba 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_selected_element.ts
+++ b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_selected_element.ts
@@ -16,6 +16,7 @@
 import './info_svg_element.js';
 import './google_photos_shared_album_dialog_element.js';
 
+import {isNonEmptyArray} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js';
 import {assert} from 'chrome://resources/js/assert.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
 
@@ -23,7 +24,7 @@
 import {isGooglePhotosSharedAlbumsEnabled, isPersonalizationJellyEnabled} from '../load_time_booleans.js';
 import {Paths} from '../personalization_router_element.js';
 import {WithPersonalizationStore} from '../personalization_store.js';
-import {getCheckmarkIcon, isNonEmptyArray} from '../utils.js';
+import {getCheckmarkIcon} from '../utils.js';
 
 import {getLocalStorageAttribution, getWallpaperAriaLabel, getWallpaperLayoutEnum, getWallpaperSrc} from './utils.js';
 import {getDailyRefreshState, selectGooglePhotosAlbum, setCurrentWallpaperLayout, setDailyRefreshCollectionId, updateDailyRefreshWallpaper} from './wallpaper_controller.js';
diff --git a/ash/webui/shimless_rma/resources/BUILD.gn b/ash/webui/shimless_rma/resources/BUILD.gn
index 8165ecc..8f9ce8e 100644
--- a/ash/webui/shimless_rma/resources/BUILD.gn
+++ b/ash/webui/shimless_rma/resources/BUILD.gn
@@ -68,10 +68,11 @@
 
   non_web_component_files = [
     "data.js",
+    "events.ts",
     "fake_data.js",
     "fake_shimless_rma_service.js",
     "mojo_interface_provider.js",
-    "shimless_rma_util.js",
+    "shimless_rma_util.ts",
   ]
 
   mojo_files = [ "$root_gen_dir/mojom-webui/ash/webui/shimless_rma/mojom/shimless_rma.mojom-webui.js" ]
diff --git a/ash/webui/shimless_rma/resources/events.ts b/ash/webui/shimless_rma/resources/events.ts
new file mode 100644
index 0000000..ed3b15f5b
--- /dev/null
+++ b/ash/webui/shimless_rma/resources/events.ts
@@ -0,0 +1,34 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {StateResult} from './shimless_rma.mojom-webui.js';
+
+export const DISABLE_NEXT_BUTTON = 'disable-next-button';
+export type DisableNextButtonEvent = CustomEvent<boolean>;
+
+export const DISABLE_ALL_BUTTONS = 'disable-all-buttons';
+export type DisableAllButtonsEvent =
+    CustomEvent<{showBusyStateOverlay: boolean}>;
+
+export const ENABLE_ALL_BUTTONS = 'enable-all-buttons';
+export type EnableAllButtonsEvent = CustomEvent;
+
+export const TRANSITION_STATE = 'transition-state';
+export type TransitionStateEvent =
+    CustomEvent<() => Promise<{stateResult: StateResult}>>;
+
+export const CLICK_NEXT_BUTTON = 'click-next-button';
+export type ClickNextButtonEvent = CustomEvent;
+
+type ExtractDetail<T> = T extends CustomEvent<infer U>? U : never;
+
+/**
+ * Constructs a CustomEvent with the given event type and details.
+ * The event will bubble up through elements and components.
+ */
+export function createCustomEvent<T extends keyof HTMLElementEventMap>(
+    type: T,
+    detail: ExtractDetail<HTMLElementEventMap[T]>): CustomEvent<typeof detail> {
+  return new CustomEvent(type, {bubbles: true, composed: true, detail});
+}
diff --git a/ash/webui/shimless_rma/resources/shimless_rma_util.js b/ash/webui/shimless_rma/resources/shimless_rma_util.js
deleted file mode 100644
index 59cd2c40..0000000
--- a/ash/webui/shimless_rma/resources/shimless_rma_util.js
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import {assert} from 'chrome://resources/ash/common/assert.js';
-import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js';
-import {afterNextRender} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {StateResult} from './shimless_rma.mojom-webui.js';
-
-/**
- * @param {!HTMLElement} element
- */
-function makeElementTabbable(element) {
-  element.setAttribute('tabindex', '0');
-}
-
-/**
- * @param {!HTMLElement} element
- */
-function removeElementFromKeyboardNavigation(element) {
-  element.setAttribute('tabindex', '-1');
-}
-
-/**
- * Disables the next button from being clicked.
- * @param {!HTMLElement} element
- */
-export function disableNextButton(element) {
-  element.dispatchEvent(new CustomEvent(
-      'disable-next-button',
-      {bubbles: true, composed: true, detail: true},
-      ));
-}
-
-/**
- * Enables the next button to be clicked.
- * @param {!HTMLElement} element
- */
-export function enableNextButton(element) {
-  element.dispatchEvent(new CustomEvent(
-      'disable-next-button',
-      {bubbles: true, composed: true, detail: false},
-      ));
-}
-
-/**
- * Disables all inputs on the page.
- * @param {!HTMLElement} element
- * @param {boolean} showBusyStateOverlay
- */
-export function disableAllButtons(element, showBusyStateOverlay) {
-  element.dispatchEvent(new CustomEvent(
-      'disable-all-buttons',
-      {bubbles: true, composed: true, detail: {showBusyStateOverlay}},
-      ));
-}
-
-/**
- * Enables all inputs on the page.
- * @param {!HTMLElement} element
- */
-export function enableAllButtons(element) {
-  element.dispatchEvent(new CustomEvent(
-      'enable-all-buttons',
-      {
-        bubbles: true,
-        composed: true,
-      },
-      ));
-}
-
-/**
- * Dispatches an event captured by shimless_rma.js that will execute `fn`,
- * process the result, then transition to the next state.
- * @param {!HTMLElement} element
- * @param {!function(): !Promise<!{stateResult: !StateResult}>} fn
- */
-export function executeThenTransitionState(element, fn) {
-  element.dispatchEvent(new CustomEvent(
-      'transition-state',
-      {bubbles: true, composed: true, detail: fn},
-      ));
-}
-
-/**
- * Dispatches an event to click the next button.
- * @param {!HTMLElement} element
- */
-export function dispatchNextButtonClick(element) {
-  element.dispatchEvent(new CustomEvent('click-next-button', {
-    bubbles: true,
-    composed: true,
-  }));
-}
-
-/**
- * Make the first non-disabled component in the list tabbable
- * and remove the remaining components from keyboard navigation.
- * @param {!HTMLElement} element
- * @param {boolean} isFirstClickableComponent
- */
-export function modifyTabbableElement(element, isFirstClickableComponent) {
-  isFirstClickableComponent ? makeElementTabbable(element) :
-                              removeElementFromKeyboardNavigation(element);
-}
-
-/**
- * Sets the focus on the page title.
- * @param {!HTMLElement} element
- */
-export function focusPageTitle(element) {
-  const pageTitle = element.shadowRoot.querySelector('h1');
-  assert(pageTitle);
-  afterNextRender(element, () => {
-    pageTitle.focus();
-  });
-}
-
-/**
- * @returns whether the "Compliance Check" flag is enabled.
- */
-export function isComplianceCheckEnabled() {
-  return loadTimeData.getBoolean('complianceCheckEnabled');
-}
-
-/**
- * @returns whether the "SKU description" flag is enabled.
- */
-export function isSkuDescriptionEnabled() {
-  return loadTimeData.getBoolean('skuDescriptionEnabled');
-}
diff --git a/ash/webui/shimless_rma/resources/shimless_rma_util.ts b/ash/webui/shimless_rma/resources/shimless_rma_util.ts
new file mode 100644
index 0000000..6b93b695
--- /dev/null
+++ b/ash/webui/shimless_rma/resources/shimless_rma_util.ts
@@ -0,0 +1,110 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js';
+import {assert} from 'chrome://resources/js/assert.js';
+import {afterNextRender} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {CLICK_NEXT_BUTTON, ClickNextButtonEvent, createCustomEvent, DISABLE_ALL_BUTTONS, DISABLE_NEXT_BUTTON, DisableAllButtonsEvent, DisableNextButtonEvent, ENABLE_ALL_BUTTONS, EnableAllButtonsEvent, TRANSITION_STATE, TransitionStateEvent} from './events.js';
+import {StateResult} from './shimless_rma.mojom-webui.js';
+
+declare global {
+  interface HTMLElementEventMap {
+    [DISABLE_NEXT_BUTTON]: DisableNextButtonEvent;
+    [DISABLE_ALL_BUTTONS]: DisableAllButtonsEvent;
+    [ENABLE_ALL_BUTTONS]: EnableAllButtonsEvent;
+    [TRANSITION_STATE]: TransitionStateEvent;
+    [CLICK_NEXT_BUTTON]: ClickNextButtonEvent;
+  }
+}
+
+function makeElementTabbable(element: HTMLElement): void {
+  element.setAttribute('tabindex', '0');
+}
+
+function removeElementFromKeyboardNavigation(element: HTMLElement): void {
+  element.setAttribute('tabindex', '-1');
+}
+
+/**
+ * Disables the next button from being clicked.
+ */
+export function disableNextButton(element: HTMLElement): void {
+  element.dispatchEvent(createCustomEvent(DISABLE_NEXT_BUTTON, true));
+}
+
+/**
+ * Enables the next button to be clicked.
+ */
+export function enableNextButton(element: HTMLElement): void {
+  element.dispatchEvent(createCustomEvent(DISABLE_NEXT_BUTTON, false));
+}
+
+/**
+ * Disables all inputs on the page.
+ */
+export function disableAllButtons(
+    element: HTMLElement, showBusyStateOverlay: boolean): void {
+  element.dispatchEvent(
+      createCustomEvent(DISABLE_ALL_BUTTONS, {showBusyStateOverlay}));
+}
+
+/**
+ * Enables all inputs on the page.
+ */
+export function enableAllButtons(element: HTMLElement): void {
+  element.dispatchEvent(createCustomEvent(ENABLE_ALL_BUTTONS, {}));
+}
+
+/**
+ * Dispatches an event captured by shimless_rma.js that will execute `fn`,
+ * process the result, then transition to the next state.
+ */
+export function executeThenTransitionState(
+    element: HTMLElement, fn: () => Promise<{stateResult: StateResult}>): void {
+  element.dispatchEvent(createCustomEvent(TRANSITION_STATE, fn));
+}
+
+/**
+ * Dispatches an event to click the next button.
+ */
+export function dispatchNextButtonClick(element: HTMLElement): void {
+  element.dispatchEvent(createCustomEvent(CLICK_NEXT_BUTTON, {}));
+}
+
+/**
+ * Make the first non-disabled component in the list tabbable
+ * and remove the remaining components from keyboard navigation.
+ */
+export function modifyTabbableElement(
+    element: HTMLElement, isFirstClickableComponent: boolean): void {
+  isFirstClickableComponent ? makeElementTabbable(element) :
+                              removeElementFromKeyboardNavigation(element);
+}
+
+/**
+ * Sets the focus on the page title.
+ */
+export function focusPageTitle(element: HTMLElement): void {
+  const pageTitle: HTMLHeadingElement|null =
+      element!.shadowRoot!.querySelector('h1');
+  assert(pageTitle);
+  afterNextRender(element, () => {
+    pageTitle.focus();
+  });
+}
+
+/**
+ * @returns whether the "Compliance Check" flag is enabled.
+ */
+export function isComplianceCheckEnabled(): boolean {
+  return loadTimeData.getBoolean('complianceCheckEnabled');
+}
+
+/**
+ * @returns whether the "SKU description" flag is enabled.
+ */
+export function isSkuDescriptionEnabled(): boolean {
+  return loadTimeData.getBoolean('skuDescriptionEnabled');
+}
diff --git a/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table_unittest.cc b/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table_unittest.cc
index 59a0d6d..5b9163e 100644
--- a/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table_unittest.cc
+++ b/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table_unittest.cc
@@ -22,9 +22,9 @@
 namespace {
 
 // The total number of Ash accelerators.
-constexpr int kAshAcceleratorsTotalNum = 151;
+constexpr int kAshAcceleratorsTotalNum = 152;
 // The hash of Ash accelerators.
-constexpr char kAshAcceleratorsHash[] = "7246ad43f69748fb249bc35f5ecd5265";
+constexpr char kAshAcceleratorsHash[] = "d86efe92af0f98f458b6c7eedd050123";
 
 std::string ToActionName(ash::AcceleratorAction action) {
   return base::StrCat(
diff --git a/ash/wm/overview/overview_grid.cc b/ash/wm/overview/overview_grid.cc
index 4f264b95..d4e10bd0 100644
--- a/ash/wm/overview/overview_grid.cc
+++ b/ash/wm/overview/overview_grid.cc
@@ -906,7 +906,6 @@
             ? std::make_optional(
                   split_view_drag_indicators_->current_window_dragging_state())
             : std::nullopt,
-        /*divider_changed=*/false,
         /*account_for_hotseat=*/true);
     SetBoundsAndUpdatePositions(grid_bounds, ignored_items, /*animate=*/true);
   }
@@ -997,7 +996,7 @@
   // Update the grid's bounds.
   const gfx::Rect wanted_grid_bounds = GetGridBoundsInScreen(
       root_window_, std::make_optional(window_dragging_state),
-      /*divider_changed=*/false, /*account_for_hotseat=*/true);
+      /*account_for_hotseat=*/true);
   if (bounds_ != wanted_grid_bounds) {
     base::flat_set<OverviewItemBase*> ignored_items;
     if (dragged_item)
@@ -2314,7 +2313,6 @@
   SetBoundsAndUpdatePositions(
       GetGridBoundsInScreen(root_window_,
                             /*window_dragging_state=*/std::nullopt,
-                            /*divider_changed=*/true,
                             /*account_for_hotseat=*/true),
       /*ignored_items=*/{}, /*animate=*/false);
 }
diff --git a/ash/wm/overview/overview_utils.cc b/ash/wm/overview/overview_utils.cc
index 1bbb1a2..1e9a6c0 100644
--- a/ash/wm/overview/overview_utils.cc
+++ b/ash/wm/overview/overview_utils.cc
@@ -163,7 +163,6 @@
 gfx::Rect GetGridBoundsInScreen(aura::Window* target_root) {
   return GetGridBoundsInScreen(target_root,
                                /*window_dragging_state=*/std::nullopt,
-                               /*divider_changed=*/false,
                                /*account_for_hotseat=*/true);
 }
 
@@ -171,7 +170,6 @@
     aura::Window* target_root,
     std::optional<SplitViewDragIndicators::WindowDraggingState>
         window_dragging_state,
-    bool divider_changed,
     bool account_for_hotseat) {
   auto* split_view_controller = SplitViewController::Get(target_root);
   SplitViewController::State state = split_view_controller->state();
@@ -268,11 +266,12 @@
     }
   }
 
-  if (!divider_changed) {
+  if (!opposite_position) {
+    // `opposite_position` is only non-empty if we are in split view state not
+    // `kNoSnap`.
     return bounds;
   }
 
-  DCHECK(opposite_position);
   const bool horizontal = IsLayoutHorizontal(target_root);
   const int min_length =
       (horizontal ? work_area.width() : work_area.height()) / 3;
@@ -323,7 +322,6 @@
   // The hotseat bounds do not affect splitview after a window is snapped, so
   // the aspect ratio should reflect it and not worry about the hotseat.
   return gfx::RectF(GetGridBoundsInScreen(root_window, window_dragging_state,
-                                          /*divider_changed=*/false,
                                           /*account_for_hotseat=*/false));
 }
 
diff --git a/ash/wm/overview/overview_utils.h b/ash/wm/overview/overview_utils.h
index 7e8233a..3e82ff1 100644
--- a/ash/wm/overview/overview_utils.h
+++ b/ash/wm/overview/overview_utils.h
@@ -77,7 +77,6 @@
     aura::Window* target_root,
     std::optional<SplitViewDragIndicators::WindowDraggingState>
         window_dragging_state,
-    bool divider_changed,
     bool account_for_hotseat);
 
 // Gets the bounds of a window if it were to be snapped or about to be snapped
diff --git a/base/allocator/partition_allocator/src/partition_alloc/address_space_randomization.h b/base/allocator/partition_allocator/src/partition_alloc/address_space_randomization.h
index 90882673..5e28dfc 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/address_space_randomization.h
+++ b/base/allocator/partition_allocator/src/partition_alloc/address_space_randomization.h
@@ -117,10 +117,12 @@
 
       // Restrict the address range on Android to avoid a large performance
       // regression in single-process WebViews. See https://crbug.com/837640.
-      PA_ALWAYS_INLINE constexpr uintptr_t ASLRMask() {
+      PA_ALWAYS_INLINE PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR uintptr_t
+      ASLRMask() {
         return AslrMask(30);
       }
-      PA_ALWAYS_INLINE constexpr uintptr_t ASLROffset() {
+      PA_ALWAYS_INLINE PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR uintptr_t
+      ASLROffset() {
         return AslrAddress(0x20000000ULL);
       }
 
diff --git a/base/allocator/partition_allocator/src/partition_alloc/page_allocator_constants.h b/base/allocator/partition_allocator/src/partition_alloc/page_allocator_constants.h
index 8f11cf1..1707952 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/page_allocator_constants.h
+++ b/base/allocator/partition_allocator/src/partition_alloc/page_allocator_constants.h
@@ -25,7 +25,7 @@
 // elimination.
 #define PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR __attribute__((const))
 
-#elif BUILDFLAG(IS_LINUX) && defined(ARCH_CPU_ARM64)
+#elif (BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX)) && defined(ARCH_CPU_ARM64)
 // This should work for all POSIX (if needed), but currently all other
 // supported OS/architecture combinations use either hard-coded values
 // (such as x86) or have means to determine these values without needing
@@ -92,7 +92,7 @@
   return 14;  // 16kB
 #elif BUILDFLAG(IS_APPLE) && defined(ARCH_CPU_64_BITS)
   return static_cast<size_t>(vm_page_shift);
-#elif BUILDFLAG(IS_LINUX) && defined(ARCH_CPU_ARM64)
+#elif (BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX)) && defined(ARCH_CPU_ARM64)
   // arm64 supports 4kb (shift = 12), 16kb (shift = 14), and 64kb (shift = 16)
   // page sizes. Retrieve from or initialize cache.
   size_t shift = page_characteristics.shift.load(std::memory_order_relaxed);
@@ -113,7 +113,7 @@
   // This is literally equivalent to |1 << PageAllocationGranularityShift()|
   // below, but was separated out for IS_APPLE to avoid << on a non-constexpr.
   return vm_page_size;
-#elif BUILDFLAG(IS_LINUX) && defined(ARCH_CPU_ARM64)
+#elif (BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX)) && defined(ARCH_CPU_ARM64)
   // arm64 supports 4kb, 16kb, and 64kb page sizes. Retrieve from or
   // initialize cache.
   size_t size = page_characteristics.size.load(std::memory_order_relaxed);
@@ -152,10 +152,11 @@
 PA_ALWAYS_INLINE PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR size_t
 SystemPageSize() {
 #if (BUILDFLAG(IS_APPLE) && defined(ARCH_CPU_64_BITS)) || \
+    (BUILDFLAG(IS_ANDROID) && defined(ARCH_CPU_ARM64)) || \
     (BUILDFLAG(IS_LINUX) && defined(ARCH_CPU_ARM64))
   // This is literally equivalent to |1 << SystemPageShift()| below, but was
-  // separated out for 64-bit IS_APPLE and arm64 on Linux to avoid << on a
-  // non-constexpr.
+  // separated out for 64-bit IS_APPLE and arm64 on Android/Linux to avoid <<
+  // on a non-constexpr.
   return PageAllocationGranularity();
 #else
   return 1 << SystemPageShift();
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_address_space.cc b/base/allocator/partition_allocator/src/partition_alloc/partition_address_space.cc
index faeb5262..25dbdf0 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/partition_address_space.cc
+++ b/base/allocator/partition_allocator/src/partition_alloc/partition_address_space.cc
@@ -420,11 +420,12 @@
 }
 #endif
 
-#if BUILDFLAG(IS_LINUX) && defined(ARCH_CPU_ARM64)
+#if (BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX)) && defined(ARCH_CPU_ARM64)
 
 PageCharacteristics page_characteristics;
 
-#endif  // BUILDFLAG(IS_LINUX) && defined(ARCH_CPU_ARM64)
+#endif  // (BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX)) &&
+        // defined(ARCH_CPU_ARM64)
 
 #endif  // BUILDFLAG(HAS_64_BIT_POINTERS)
 
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_constants.h b/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_constants.h
index a572b422..0312f23 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_constants.h
+++ b/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_constants.h
@@ -111,6 +111,7 @@
   return 18;  // 256 KiB
 }
 #elif (BUILDFLAG(IS_APPLE) && defined(ARCH_CPU_64_BITS)) || \
+    (BUILDFLAG(IS_ANDROID) && defined(ARCH_CPU_ARM64)) ||   \
     (BUILDFLAG(IS_LINUX) && defined(ARCH_CPU_ARM64))
 PA_ALWAYS_INLINE PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR size_t
 PartitionPageShift() {
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_page_constants.h b/base/allocator/partition_allocator/src/partition_alloc/partition_page_constants.h
index b0707c7..67ea004 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/partition_page_constants.h
+++ b/base/allocator/partition_allocator/src/partition_alloc/partition_page_constants.h
@@ -16,7 +16,7 @@
 // (1 << 12 or 1 << 14), as checked in PartitionRoot::Init(). And
 // PartitionPageSize() is 4 times the OS page size.
 static constexpr size_t kMaxSlotsPerSlotSpan = 4 * (1 << 14) / kSmallestBucket;
-#elif BUILDFLAG(IS_LINUX) && defined(ARCH_CPU_ARM64)
+#elif (BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX)) && defined(ARCH_CPU_ARM64)
 // System page size can be 4, 16, or 64 kiB on Linux on arm64. 64 kiB is
 // currently (kMaxSlotsPerSlotSpanBits == 13) not supported by the code,
 // so we use the 16 kiB maximum (64 kiB will crash).
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_root.cc b/base/allocator/partition_allocator/src/partition_alloc/partition_root.cc
index 27f6725..0a0db0c 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/partition_root.cc
+++ b/base/allocator/partition_allocator/src/partition_alloc/partition_root.cc
@@ -375,7 +375,9 @@
   constexpr size_t kMaxSlotCount =
       (PartitionPageSize() * kMaxPartitionPagesPerRegularSlotSpan) /
       MinPurgeableSlotSize();
-#elif BUILDFLAG(IS_APPLE) || (BUILDFLAG(IS_LINUX) && defined(ARCH_CPU_ARM64))
+#elif BUILDFLAG(IS_APPLE) ||                           \
+    ((BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX)) && \
+     defined(ARCH_CPU_ARM64))
   // It's better for slot_usage to be stack-allocated and fixed-size, which
   // demands that its size be constexpr. On IS_APPLE and Linux on arm64,
   // PartitionPageSize() is always SystemPageSize() << 2, so regardless of
diff --git a/base/immediate_crash.h b/base/immediate_crash.h
index 17e9257..9e02690 100644
--- a/base/immediate_crash.h
+++ b/base/immediate_crash.h
@@ -167,7 +167,9 @@
   // handlers. We want to dump coverage information so we'll do that
   // here explicitly too.
 #if BUILDFLAG(IS_LINUX)
-  __llvm_profile_write_file();
+  if (__llvm_profile_write_file) {
+    __llvm_profile_write_file();
+  }
 #endif  // BUILDFLAG(IS_LINUX)
   exit(-1);
 #else   // BUILDFLAG(USE_FUZZING_ENGINE)
diff --git a/build/android/pylib/instrumentation/instrumentation_test_instance.py b/build/android/pylib/instrumentation/instrumentation_test_instance.py
index c3e2968..b22c6a84 100644
--- a/build/android/pylib/instrumentation/instrumentation_test_instance.py
+++ b/build/android/pylib/instrumentation/instrumentation_test_instance.py
@@ -691,13 +691,15 @@
       self._apk_under_test = apk_helper.ToHelper(apk_under_test_path)
 
     test_apk_path = args.test_apk
-    if not os.path.exists(test_apk_path):
+    if (not args.test_apk.endswith('.apk')
+        and not args.test_apk.endswith('.apks')):
       test_apk_path = os.path.join(
           constants.GetOutDirectory(), constants.SDK_BUILD_APKS_DIR,
           '%s.apk' % args.test_apk)
-      # TODO(jbudorick): Move the realpath up to the argument parser once
-      # APK-by-name is no longer supported.
-      test_apk_path = os.path.realpath(test_apk_path)
+
+    # TODO(jbudorick): Move the realpath up to the argument parser once
+    # APK-by-name is no longer supported.
+    test_apk_path = os.path.realpath(test_apk_path)
 
     if not os.path.exists(test_apk_path):
       error_func('Unable to find test APK: %s' % test_apk_path)
diff --git a/build/chromeos/test_runner.py b/build/chromeos/test_runner.py
index f01e553..bdc7008 100755
--- a/build/chromeos/test_runner.py
+++ b/build/chromeos/test_runner.py
@@ -57,6 +57,7 @@
     '/var/log/chrome/',
     '/var/log/messages',
     '/var/log/ui/',
+    '/var/log/lacros/',
 ]
 
 TAST_DEBUG_DOC = 'https://bit.ly/2LgvIXz'
diff --git a/build/fuchsia/update_product_bundles.py b/build/fuchsia/update_product_bundles.py
index 1919d89..8c3ddb9 100755
--- a/build/fuchsia/update_product_bundles.py
+++ b/build/fuchsia/update_product_bundles.py
@@ -22,24 +22,10 @@
 
 # TODO(crbug/1361089): Remove when the old scripts have been deprecated.
 _IMAGE_TO_PRODUCT_BUNDLE = {
-    'core.x64-dfv2-release':
-    'core.x64-dfv2',
     'qemu.arm64':
     'terminal.qemu-arm64',
     'qemu.x64':
     'terminal.x64',
-    'workstation_eng.chromebook-x64-dfv2-release':
-    'workstation_eng.chromebook-x64-dfv2',
-    'workstation_eng.chromebook-x64-release':
-    'workstation_eng.chromebook-x64',
-    'workstation_eng.qemu-x64-release':
-    'workstation_eng.qemu-x64',
-    'smart_display_eng_arrested.astro-release':
-    'smart_display_eng_arrested.astro',
-    'smart_display_max_eng_arrested.sherlock-release':
-    'smart_display_max_eng_arrested.sherlock',
-    'smart_display_m3_latest_eng_paused.nelson-release':
-    'smart_display_m3_latest_eng_paused.nelson',
 }
 
 
@@ -52,7 +38,13 @@
     if image in _IMAGE_TO_PRODUCT_BUNDLE:
       logging.warning(f'Image name {image} has been deprecated. Use '
                       f'{_IMAGE_TO_PRODUCT_BUNDLE.get(image)} instead.')
-    product_bundle_list.append(_IMAGE_TO_PRODUCT_BUNDLE.get(image, image))
+      product_bundle_list.append(_IMAGE_TO_PRODUCT_BUNDLE[image])
+    else:
+      if image.endswith('-release'):
+        image = image[:-len('-release')]
+        logging.warning(f'Image name {image}-release has been deprecated. Use '
+                        f'{image} instead.')
+      product_bundle_list.append(image)
   return product_bundle_list
 
 
diff --git a/build/fuchsia/update_product_bundles_test.py b/build/fuchsia/update_product_bundles_test.py
index 0540b27..be1aa72 100755
--- a/build/fuchsia/update_product_bundles_test.py
+++ b/build/fuchsia/update_product_bundles_test.py
@@ -32,6 +32,11 @@
         update_product_bundles.convert_to_products(['unknown-image']),
         ['unknown-image'])
 
+  def testConvertToProductBundleRemovesReleaseSuffix(self):
+    self.assertEqual(
+        update_product_bundles.convert_to_products(
+            ['smart_display_eng.astro-release']), ['smart_display_eng.astro'])
+
   def testConvertToProductBundleWarnsDeprecated(self):
     with self.assertLogs(level='WARNING') as logs:
       deprecated_images = [
diff --git a/buildtools/deps_revisions.gni b/buildtools/deps_revisions.gni
index 13286e31..78c28356 100644
--- a/buildtools/deps_revisions.gni
+++ b/buildtools/deps_revisions.gni
@@ -5,5 +5,5 @@
 declare_args() {
   # Used to cause full rebuilds on libc++ rolls. This should be kept in sync
   # with the libcxx_revision vars in //DEPS.
-  libcxx_revision = "28d7125795ff7da27512de569bb539e7ba44cb62"
+  libcxx_revision = "d855d8bc2ef4a063c552236b57ed0b1ab2e6e0c1"
 }
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index a609982..8850a15 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -590,7 +590,6 @@
       "//components/webapk/android/libs/client:java",
       "//components/webapk/android/libs/common:java",
       "//components/webapps/browser/android:java",
-      "//components/webapps/common/android:webapk_install_java",
       "//components/webauthn/android:java",
       "//components/webrtc/android:java",
       "//components/webxr/android:xr_java",
@@ -2570,7 +2569,6 @@
       "java/src/org/chromium/chrome/browser/services/gcm/GCMBackgroundService.java",
       "java/src/org/chromium/chrome/browser/services/gcm/InvalidationGcmUpstreamSender.java",
       "java/src/org/chromium/chrome/browser/tracing/TracingNotificationService.java",
-      "java/src/org/chromium/chrome/browser/webapps/WebApkInstallCoordinatorService.java",
     ]
     deps = [
       ":chrome_base_module_resources",
@@ -3634,7 +3632,6 @@
     "java/src/org/chromium/chrome/browser/usage_stats/UsageStatsBridge.java",
     "java/src/org/chromium/chrome/browser/webapps/WebApkDataProvider.java",
     "java/src/org/chromium/chrome/browser/webapps/WebApkHandlerDelegate.java",
-    "java/src/org/chromium/chrome/browser/webapps/WebApkInstallCoordinatorBridge.java",
     "java/src/org/chromium/chrome/browser/webapps/WebApkInstallService.java",
     "java/src/org/chromium/chrome/browser/webapps/WebApkInstaller.java",
     "java/src/org/chromium/chrome/browser/webapps/WebApkPostShareTargetNavigator.java",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 9fb7a39..6685de3 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -838,7 +838,6 @@
   "java/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerProcessor.java",
   "java/src/org/chromium/chrome/browser/offlinepages/ClientId.java",
   "java/src/org/chromium/chrome/browser/offlinepages/DeletedPageInfo.java",
-  "java/src/org/chromium/chrome/browser/offlinepages/GetPagesByNamespaceForLivePageSharingCallback.java",
   "java/src/org/chromium/chrome/browser/offlinepages/OfflineBackgroundTask.java",
   "java/src/org/chromium/chrome/browser/offlinepages/OfflinePageArchivePublisherBridge.java",
   "java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java",
@@ -849,7 +848,6 @@
   "java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java",
   "java/src/org/chromium/chrome/browser/offlinepages/PublishPageCallback.java",
   "java/src/org/chromium/chrome/browser/offlinepages/RequestCoordinatorBridge.java",
-  "java/src/org/chromium/chrome/browser/offlinepages/SavePageAndShareCallback.java",
   "java/src/org/chromium/chrome/browser/offlinepages/SavePageRequest.java",
   "java/src/org/chromium/chrome/browser/offlinepages/TaskExtrasPacker.java",
   "java/src/org/chromium/chrome/browser/offlinepages/TriggerConditions.java",
@@ -1192,8 +1190,6 @@
   "java/src/org/chromium/chrome/browser/webapps/WebApkIconNameUpdateCustomView.java",
   "java/src/org/chromium/chrome/browser/webapps/WebApkIconNameUpdateDialog.java",
   "java/src/org/chromium/chrome/browser/webapps/WebApkInstallBroadcastReceiver.java",
-  "java/src/org/chromium/chrome/browser/webapps/WebApkInstallCoordinatorBridge.java",
-  "java/src/org/chromium/chrome/browser/webapps/WebApkInstallCoordinatorServiceImpl.java",
   "java/src/org/chromium/chrome/browser/webapps/WebApkInstallService.java",
   "java/src/org/chromium/chrome/browser/webapps/WebApkInstaller.java",
   "java/src/org/chromium/chrome/browser/webapps/WebApkIntentDataProviderFactory.java",
diff --git a/chrome/android/expectations/monochrome_public_bundle__chrome.AndroidManifest.expected b/chrome/android/expectations/monochrome_public_bundle__chrome.AndroidManifest.expected
index afcd221..9e4bc5a0 100644
--- a/chrome/android/expectations/monochrome_public_bundle__chrome.AndroidManifest.expected
+++ b/chrome/android/expectations/monochrome_public_bundle__chrome.AndroidManifest.expected
@@ -999,13 +999,6 @@
         android:name="org.chromium.chrome.browser.tracing.TracingNotificationService"
         android:exported="false">
     </service>  # DIFF-ANCHOR: c26364a8
-    <service  # DIFF-ANCHOR: 878b448b
-        android:name="org.chromium.chrome.browser.webapps.WebApkInstallCoordinatorService"
-        android:exported="true">
-      <intent-filter>  # DIFF-ANCHOR: 875093ee
-        <action android:name="org.chromium.intent.action.INSTALL_WEB_APK"/>
-      </intent-filter>  # DIFF-ANCHOR: 875093ee
-    </service>  # DIFF-ANCHOR: 878b448b
     <service  # DIFF-ANCHOR: a550decc
         android:name="org.chromium.components.background_task_scheduler.internal.BackgroundTaskJobService"
         android:exported="false"
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceCoordinator.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceCoordinator.java
index a0cfa107..e6112c3e 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceCoordinator.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceCoordinator.java
@@ -15,6 +15,7 @@
 import androidx.recyclerview.widget.RecyclerView;
 
 import org.chromium.base.jank_tracker.JankTracker;
+import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.app.feed.FeedActionDelegateImpl;
@@ -84,7 +85,8 @@
             Supplier<ShareDelegate> shareDelegateSupplier,
             WindowAndroid windowAndroid,
             JankTracker jankTracker,
-            TabModelSelector tabModelSelector) {
+            TabModelSelector tabModelSelector,
+            @NonNull ObservableSupplier<Integer> tabStripHeightSupplier) {
         mActivity = activity;
         mJankTracker = jankTracker;
         mExploreSurfaceNavigationDelegate = new ExploreSurfaceNavigationDelegate(parentTabSupplier);
@@ -122,7 +124,7 @@
                                 BookmarkModel.getForProfile(profile),
                                 tabModelSelector),
                         HelpAndFeedbackLauncherImpl.getForProfile(profile),
-                        tabModelSelector);
+                        tabStripHeightSupplier);
 
         mFeedSurfaceCoordinator.getView().setId(R.id.start_surface_explore_view);
         // TODO(crbug.com/982018): Customize surface background for incognito and dark mode.
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceCoordinatorFactory.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceCoordinatorFactory.java
index 4de13fe7..86665b5 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceCoordinatorFactory.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceCoordinatorFactory.java
@@ -11,6 +11,7 @@
 import androidx.annotation.Nullable;
 
 import org.chromium.base.jank_tracker.JankTracker;
+import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.browser.feed.FeedSwipeRefreshLayout;
 import org.chromium.chrome.browser.feed.ScrollableContainerDelegate;
@@ -42,7 +43,7 @@
     private final long mEmbeddingSurfaceConstructedTimeNs;
     @Nullable private final FeedSwipeRefreshLayout mSwipeRefreshLayout;
     @NonNull private final ViewGroup mParentView;
-    private ExploreSurfaceFeedLifecycleManager mExploreSurfaceFeedLifecycleManager;
+    private final ObservableSupplier<Integer> mTabStripHeightSupplier;
 
     /**
      * @param activity The current {@link Activity}.
@@ -58,7 +59,8 @@
      * @param tabModelSelector The current {@link TabModelSelector}.
      * @param toolbarSupplier Supplies the {@link Toolbar}.
      * @param embeddingSurfaceConstructedTimeNs Timestamp taken when the caller was constructed.
-     * @param swipeRefreshLayout The layout to support pull-to-refresg.
+     * @param swipeRefreshLayout The layout to support pull-to-refresh.
+     * @param tabStripHeightSupplier Supplier for the tab strip height.
      */
     ExploreSurfaceCoordinatorFactory(
             @NonNull Activity activity,
@@ -74,7 +76,8 @@
             @NonNull TabModelSelector tabModelSelector,
             @NonNull Supplier<Toolbar> toolbarSupplier,
             long embeddingSurfaceConstructedTimeNs,
-            @Nullable FeedSwipeRefreshLayout swipeRefreshLayout) {
+            @Nullable FeedSwipeRefreshLayout swipeRefreshLayout,
+            @NonNull ObservableSupplier<Integer> tabStripHeightSupplier) {
         mActivity = activity;
         mParentView = parentView;
         mParentTabSupplier = parentTabSupplier;
@@ -91,6 +94,7 @@
         mPropertyModelChangeProcessor =
                 PropertyModelChangeProcessor.create(
                         containerPropertyModel, parentView, ExploreSurfaceViewBinder::bind);
+        mTabStripHeightSupplier = tabStripHeightSupplier;
     }
 
     /**
@@ -122,6 +126,7 @@
                 mShareDelegateSupplier,
                 mWindowAndroid,
                 mJankTracker,
-                mTabModelSelector);
+                mTabModelSelector,
+                mTabStripHeightSupplier);
     }
 }
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
index 2a5faaa..9a8bd8a 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
@@ -207,6 +207,7 @@
     private QueryTileSection mQueryTileSection;
     private boolean mIsMVTilesInitialized;
     private final boolean mIsSurfacePolishEnabled;
+    private final ObservableSupplier<Integer> mTabStripHeightSupplier;
 
     private class ScrollableContainerDelegateImpl implements ScrollableContainerDelegate {
         @Override
@@ -248,7 +249,7 @@
      * @param windowAndroid The current {@link WindowAndroid}.a
      * @param jankTracker asd
      * @param containerView The container {@link ViewGroup} for this ui, also the root view for
-     *         StartSurface.
+     *     StartSurface.
      * @param dynamicResourceLoaderSupplier Supplies the current {@link DynamicResourceLoader}.
      * @param tabModelSelector The current {@link TabModelSelector}.
      * @param browserControlsManager Manages the browser controls.
@@ -265,9 +266,10 @@
      * @param toolbarSupplier Supplies the {@link Toolbar}.
      * @param backPressManager {@link BackPressManager} to handle back press.
      * @param incognitoReauthControllerSupplier {@link OneshotSupplier<IncognitoReauthController>}
-     *         to detect pending re-auth when tab switcher is shown.
+     *     to detect pending re-auth when tab switcher is shown.
      * @param profileSupplier Supplies the {@Profile}.
      * @param tabSwitcherClickHandler The {@link OnClickListener} for the tab switcher button.
+     * @param tabStripHeightSupplier Supplier for the tab strip height.
      */
     public StartSurfaceCoordinator(
             @NonNull Activity activity,
@@ -296,7 +298,8 @@
             BackPressManager backPressManager,
             @NonNull OneshotSupplier<IncognitoReauthController> incognitoReauthControllerSupplier,
             @NonNull OnClickListener tabSwitcherClickHandler,
-            @NonNull ObservableSupplier<Profile> profileSupplier) {
+            @NonNull ObservableSupplier<Profile> profileSupplier,
+            @NonNull ObservableSupplier<Integer> tabStripHeightSupplier) {
         mConstructedTimeNs = SystemClock.elapsedRealtimeNanos();
         mActivity = activity;
         mScrimCoordinator = scrimCoordinator;
@@ -322,6 +325,7 @@
         mToolbarSupplier = toolbarSupplier;
         mIncognitoReauthControllerSupplier = incognitoReauthControllerSupplier;
         mProfileSupplier = profileSupplier;
+        mTabStripHeightSupplier = tabStripHeightSupplier;
 
         mUseMagicSpace = mIsStartSurfaceEnabled && StartSurfaceConfiguration.useMagicSpace();
         mTabSwitcherCustomViewManagerSupplier = new ObservableSupplierImpl<>();
@@ -557,7 +561,8 @@
                             mTabModelSelector,
                             mToolbarSupplier,
                             mConstructedTimeNs,
-                            mSwipeRefreshLayout);
+                            mSwipeRefreshLayout,
+                            mTabStripHeightSupplier);
         }
         mStartSurfaceMediator.initWithNative(
                 mIsStartSurfaceEnabled ? mOmniboxStubSupplier.get() : null,
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceDelegate.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceDelegate.java
index b2b7861..2890b747 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceDelegate.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceDelegate.java
@@ -93,18 +93,18 @@
 
     /**
      * Create the {@link StartSurfaceCoordinator}
+     *
      * @param activity The {@link Activity} creates this {@link StartSurface}.
      * @param scrimCoordinator The {@link ScrimCoordinator} to control the scrim view.
      * @param sheetController A {@link BottomSheetController} to show content in the bottom sheet.
      * @param startSurfaceOneshotSupplier Supplies the {@link StartSurface}, passing the owned
-     *         supplier to StartSurface itself.
-     * @param parentTabSupplier A {@link Supplier} to provide parent tab for
-     *         StartSurface.
+     *     supplier to StartSurface itself.
+     * @param parentTabSupplier A {@link Supplier} to provide parent tab for StartSurface.
      * @param hadWarmStart Whether the activity had a warm start because the native library was
-     *         already fully loaded and initialized
+     *     already fully loaded and initialized
      * @param windowAndroid An instance of a {@link WindowAndroid}
      * @param containerView The container {@link ViewGroup} for this ui, also the root view for
-     *         StartSurface.
+     *     StartSurface.
      * @param dynamicResourceLoaderSupplier Supplies the current {@link DynamicResourceLoader}.
      * @param tabModelSelector Gives access to the current set of {@TabModel}.
      * @param browserControlsManager Manages the browser controls.
@@ -121,9 +121,10 @@
      * @param toolbarSupplier Supplies the {@link Toolbar}.
      * @param backPressManager {@link BackPressManager} to handle back press gesture.
      * @param incognitoReauthControllerSupplier {@link OneshotSupplier<IncognitoReauthController>}
-     *         to detect pending re-auth when tab switcher is shown.
+     *     to detect pending re-auth when tab switcher is shown.
      * @param tabSwitcherClickHandler The {@link OnClickListener} for the tab switcher button.
      * @param profileSupplier Supplies the {@link Profile}.
+     * @param tabStripHeightSupplier Supplier for the tab strip height.
      * @return the {@link StartSurface}
      */
     public static StartSurface createStartSurface(
@@ -153,7 +154,8 @@
             BackPressManager backPressManager,
             @NonNull OneshotSupplier<IncognitoReauthController> incognitoReauthControllerSupplier,
             @NonNull OnClickListener tabSwitcherClickHandler,
-            @NonNull ObservableSupplier<Profile> profileSupplier) {
+            @NonNull ObservableSupplier<Profile> profileSupplier,
+            @NonNull ObservableSupplier<Integer> tabStripHeightSupplier) {
         return new StartSurfaceCoordinator(
                 activity,
                 scrimCoordinator,
@@ -181,6 +183,7 @@
                 backPressManager,
                 incognitoReauthControllerSupplier,
                 tabSwitcherClickHandler,
-                profileSupplier);
+                profileSupplier,
+                tabStripHeightSupplier);
     }
 }
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/ExploreSurfaceViewBinderTest.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/ExploreSurfaceViewBinderTest.java
index c558a66..5cc9a41 100644
--- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/ExploreSurfaceViewBinderTest.java
+++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/ExploreSurfaceViewBinderTest.java
@@ -32,6 +32,7 @@
 
 import org.chromium.base.jank_tracker.PlaceholderJankTracker;
 import org.chromium.base.supplier.ObservableSupplierImpl;
+import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.browser.feed.ScrollableContainerDelegate;
@@ -48,6 +49,7 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+@Batch(Batch.PER_CLASS)
 public class ExploreSurfaceViewBinderTest {
     private ExploreSurfaceCoordinatorFactory mExploreSurfaceCoordinatorFactory;
     private ExploreSurfaceCoordinator mExploreSurfaceCoordinator;
@@ -73,6 +75,8 @@
         TestThreadUtils.runOnUiThreadBlocking(
                 () -> {
                     mPropertyModel = new PropertyModel(StartSurfaceProperties.ALL_KEYS);
+                    var tabStripHeightSupplier = new ObservableSupplierImpl<Integer>();
+                    tabStripHeightSupplier.set(0);
                     mExploreSurfaceCoordinatorFactory =
                             new ExploreSurfaceCoordinatorFactory(
                                     mActivityTestRule.getActivity(),
@@ -92,7 +96,8 @@
                                         return null;
                                     },
                                     0L,
-                                    null);
+                                    null,
+                                    tabStripHeightSupplier);
                     mExploreSurfaceCoordinator =
                             mExploreSurfaceCoordinatorFactory.create(
                                     false,
diff --git a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinatorUnitTestRule.java b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinatorUnitTestRule.java
index 363c99d7..b171305 100644
--- a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinatorUnitTestRule.java
+++ b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinatorUnitTestRule.java
@@ -267,6 +267,9 @@
         when(voiceRecognitionHandler.isVoiceSearchEnabled()).thenReturn(true);
         mIncognitoReauthControllerSupplier.set(Mockito.mock(IncognitoReauthController.class));
 
+        var tabStripHeightSupplier = new ObservableSupplierImpl<Integer>();
+        tabStripHeightSupplier.set(0);
+
         mCoordinator =
                 new StartSurfaceCoordinator(
                         mActivity,
@@ -295,7 +298,8 @@
                         new BackPressManager(),
                         mIncognitoReauthControllerSupplier,
                         null,
-                        mProfileSupplier);
+                        mProfileSupplier,
+                        tabStripHeightSupplier);
 
         Assert.assertFalse(LibraryLoader.getInstance().isLoaded());
         when(mLibraryLoader.isInitialized()).thenReturn(true);
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java
index 567fcc0..839ff465d 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java
@@ -7,7 +7,6 @@
 import android.app.Activity;
 import android.content.Context;
 import android.content.res.Configuration;
-import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.os.Build;
 import android.os.Handler;
@@ -26,6 +25,7 @@
 import androidx.appcompat.content.res.AppCompatResources;
 import androidx.recyclerview.widget.RecyclerView;
 
+import org.chromium.base.Callback;
 import org.chromium.base.CommandLine;
 import org.chromium.base.ObserverList;
 import org.chromium.base.ResettersForTesting;
@@ -33,6 +33,7 @@
 import org.chromium.base.TraceEvent;
 import org.chromium.base.jank_tracker.JankScenario;
 import org.chromium.base.jank_tracker.JankTracker;
+import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
@@ -50,7 +51,6 @@
 import org.chromium.chrome.browser.privacy.settings.PrivacyPreferencesManagerImpl;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.share.ShareDelegate;
-import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.toolbar.top.Toolbar;
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
 import org.chromium.chrome.browser.ui.native_page.TouchEnabledDelegate;
@@ -159,6 +159,8 @@
     private FeedSwipeRefreshLayout mSwipeRefreshLayout;
 
     private boolean mWebFeedHasContent;
+    private final ObservableSupplier<Integer> mTabStripHeightSupplier;
+    private final Callback<Integer> mTabStripHeightChangeCallback;
 
     /** Provides the additional capabilities needed for the container view. */
     private class RootView extends FrameLayout {
@@ -343,6 +345,7 @@
 
     /**
      * Constructs a new FeedSurfaceCoordinator.
+     *
      * @param activity The containing {@link Activity}.
      * @param snackbarManager The {@link SnackbarManager} displaying Snackbar UI.
      * @param windowAndroid The window of the page.
@@ -350,7 +353,7 @@
      * @param snapScrollHelper The {@link SnapScrollHelper} for the New Tab Page.
      * @param ntpHeader The extra header on top of the feeds for the New Tab Page.
      * @param toolbarHeight The height of the toolbar which overlaps Feed content at the top of the
-     *   view.
+     *     view.
      * @param showDarkBackground Whether is shown on dark background.
      * @param delegate The constructing {@link FeedSurfaceDelegate}.
      * @param profile The current user profile.
@@ -365,10 +368,10 @@
      * @param swipeRefreshLayout The layout to support pull-to-refresh.
      * @param overScrollDisabled Whether the overscroll effect is disabled.
      * @param viewportView The view that should be used as a container for viewport measurement
-     *   purposes, or |null| if the view returned by HybridListRenderer is to be used.
+     *     purposes, or |null| if the view returned by HybridListRenderer is to be used.
      * @param actionDelegate Implements some Feed actions.
      * @param helpAndFeedbackLauncher A HelpAndFeedbackLauncher.
-     * @param tabModelSelector TabModelSelector used to get TabModels we can observe.
+     * @param tabStripHeightSupplier Supplier for the tab strip height.
      */
     public FeedSurfaceCoordinator(
             Activity activity,
@@ -395,7 +398,7 @@
             @Nullable ViewGroup viewportView,
             FeedActionDelegate actionDelegate,
             HelpAndFeedbackLauncher helpAndFeedbackLauncher,
-            TabModelSelector tabModelSelector) {
+            @NonNull ObservableSupplier<Integer> tabStripHeightSupplier) {
         mActivity = activity;
         mSnackbarManager = snackbarManager;
         mNtpHeader = ntpHeader;
@@ -420,11 +423,18 @@
         mWebFeedHasContent = false;
         mSectionHeaderIndex = 0;
         mToolbarHeight = toolbarHeight;
-
-        Resources resources = mActivity.getResources();
+        mTabStripHeightSupplier = tabStripHeightSupplier;
 
         mRootView = new RootView(mActivity);
-        mRootView.setPadding(0, resources.getDimensionPixelOffset(R.dimen.tab_strip_height), 0, 0);
+        mRootView.setPadding(0, mTabStripHeightSupplier.get(), 0, 0);
+        mTabStripHeightChangeCallback =
+                newHeight ->
+                        mRootView.setPadding(
+                                mRootView.getPaddingLeft(),
+                                newHeight,
+                                mRootView.getPaddingRight(),
+                                mRootView.getPaddingBottom());
+        mTabStripHeightSupplier.addObserver(mTabStripHeightChangeCallback);
         mUiConfig = new UiConfig(mRootView);
         mRecyclerView = setUpView();
         mStreamViewResizer =
@@ -604,6 +614,7 @@
             mHybridListRenderer.unbind();
         }
         mRootView.removeAllViews();
+        mTabStripHeightSupplier.removeObserver(mTabStripHeightChangeCallback);
     }
 
     /**
@@ -1212,4 +1223,8 @@
     public FeedActionDelegate getActionDelegateForTesting() {
         return mActionDelegate;
     }
+
+    FrameLayout getRootViewForTesting() {
+        return mRootView;
+    }
 }
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index ee5fab53..bd25a11 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -1087,15 +1087,6 @@
             </intent-filter>
         </service>
 
-        <service
-            android:name="org.chromium.chrome.browser.webapps.WebApkInstallCoordinatorService"
-            android:exported="true"
-            tools:ignore="ExportedService">
-            <intent-filter>
-              <action android:name="org.chromium.intent.action.INSTALL_WEB_APK" />
-            </intent-filter>
-        </service>
-
 
         <receiver android:name="org.chromium.chrome.browser.announcement.AnnouncementNotificationManager$Receiver"
             android:exported="false"/>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 30f6d98..223a4352 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -768,6 +768,7 @@
             mDragDropDelegate.setDragAndDropBrowserDelegate(
                     new ChromeDragAndDropBrowserDelegate(this));
 
+            assert getToolbarManager() != null;
             mLayoutManager =
                     new LayoutManagerChromeTablet(
                             compositorViewHolder,
@@ -787,7 +788,8 @@
                             mDragDropDelegate,
                             toolbarContainerView,
                             tabHoverCardViewStub,
-                            getWindowAndroid());
+                            getWindowAndroid(),
+                            getToolbarManager().getTabStripHeightSupplier());
             mLayoutStateProviderSupplier.set(mLayoutManager);
         }
     }
@@ -839,7 +841,8 @@
                 mBackPressManager,
                 mRootUiCoordinator.getIncognitoReauthControllerSupplier(),
                 v -> onTabSwitcherClicked(),
-                mTabModelProfileSupplier);
+                mTabModelProfileSupplier,
+                getToolbarManager().getTabStripHeightSupplier());
     }
 
     private void createGridTabSwitcher(
@@ -2380,7 +2383,8 @@
                             mJankTracker,
                             getToolbarManager()::getToolbar,
                             mHomeSurfaceTracker,
-                            getTabContentManagerSupplier());
+                            getTabContentManagerSupplier(),
+                            getToolbarManager().getTabStripHeightSupplier());
         }
         return mTabDelegateFactory;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/TabbedModeTabDelegateFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/TabbedModeTabDelegateFactory.java
index 89bb38d..05d6f973 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/TabbedModeTabDelegateFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/TabbedModeTabDelegateFactory.java
@@ -6,6 +6,7 @@
 
 import android.app.Activity;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import org.chromium.base.jank_tracker.JankTracker;
@@ -73,6 +74,7 @@
     private final JankTracker mJankTracker;
     private final Supplier<Toolbar> mToolbarSupplier;
     private final HomeSurfaceTracker mHomeSurfaceTracker;
+    private final ObservableSupplier<Integer> mTabStripHeightSupplier;
 
     private NativePageFactory mNativePageFactory;
 
@@ -99,7 +101,8 @@
             JankTracker jankTracker,
             Supplier<Toolbar> toolbarSupplier,
             @Nullable HomeSurfaceTracker homeSurfaceTracker,
-            ObservableSupplier<TabContentManager> tabContentManagerSupplier) {
+            ObservableSupplier<TabContentManager> tabContentManagerSupplier,
+            @NonNull ObservableSupplier<Integer> tabStripHeightSupplier) {
         mActivity = activity;
         mAppBrowserControlsVisibilityDelegate = appBrowserControlsVisibilityDelegate;
         mShareDelegateSupplier = shareDelegateSupplier;
@@ -123,6 +126,7 @@
         mToolbarSupplier = toolbarSupplier;
         mHomeSurfaceTracker = homeSurfaceTracker;
         mTabContentManagerSupplier = tabContentManagerSupplier;
+        mTabStripHeightSupplier = tabStripHeightSupplier;
     }
 
     @Override
@@ -183,7 +187,8 @@
                             mJankTracker,
                             mToolbarSupplier,
                             mHomeSurfaceTracker,
-                            mTabContentManagerSupplier);
+                            mTabContentManagerSupplier,
+                            mTabStripHeightSupplier);
         }
         return mNativePageFactory.createNativePage(url, candidatePage, tab);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java
index 5e883acd..f1d7cf4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java
@@ -78,6 +78,7 @@
      * @param toolbarContainerView @{link View} passed to @{link StripLayoutHelper} to support tab
      *     drag and drop.
      * @param tabHoverCardViewStub The {@link ViewStub} representing the strip tab hover card.
+     * @param tabStripHeightSupplier Supplier for the tab strip height.
      */
     public LayoutManagerChromeTablet(
             LayoutManagerHost host,
@@ -97,7 +98,8 @@
             DragAndDropDelegate dragAndDropDelegate,
             View toolbarContainerView,
             @NonNull ViewStub tabHoverCardViewStub,
-            @NonNull WindowAndroid windowAndroid) {
+            @NonNull WindowAndroid windowAndroid,
+            @NonNull ObservableSupplier<Integer> tabStripHeightSupplier) {
         super(
                 host,
                 contentContainer,
@@ -125,7 +127,8 @@
                         tabHoverCardViewStub,
                         tabContentManagerSupplier,
                         browserControlsStateProvider,
-                        windowAndroid);
+                        windowAndroid,
+                        tabStripHeightSupplier);
         addSceneOverlay(mTabStripLayoutHelperManager);
         addObserver(mTabStripLayoutHelperManager.getTabSwitcherObserver());
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
index 6b95ba9..165ac71 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
@@ -290,6 +290,7 @@
      * @param tabHoverCardViewStub The {@link ViewStub} representing the strip tab hover card.
      * @param tabContentManagerSupplier Supplier of the {@link TabContentManager} instance.
      * @param browserControlsStateProvider @{@link BrowserControlsStateProvider} for drag drop.
+     * @param tabStripHeightSupplier Supplier for the tab strip height.
      */
     public StripLayoutHelperManager(
             Context context,
@@ -305,7 +306,8 @@
             @NonNull ViewStub tabHoverCardViewStub,
             ObservableSupplier<TabContentManager> tabContentManagerSupplier,
             @NonNull BrowserControlsStateProvider browserControlsStateProvider,
-            @NonNull WindowAndroid windowAndroid) {
+            @NonNull WindowAndroid windowAndroid,
+            @NonNull ObservableSupplier<Integer> tabStripHeightSupplier) {
         mUpdateHost = updateHost;
         mLayerTitleCacheSupplier = layerTitleCacheSupplier;
         mTabStripTreeProvider = new TabStripSceneLayer(context);
@@ -402,7 +404,8 @@
                             multiInstanceManager,
                             dragDropDelegate,
                             browserControlsStateProvider,
-                            windowAndroid);
+                            windowAndroid,
+                            tabStripHeightSupplier);
         }
 
         mNormalHelper =
@@ -547,7 +550,7 @@
         if (mIsHidden) {
             // When tab strip is hidden, the stable offset of this scene layer should be a negative
             // value.
-            yOffset -= mHeight;
+            yOffset -= getHeight();
         }
         mTabStripTreeProvider.pushAndUpdateStrip(
                 this,
@@ -588,9 +591,10 @@
                     getModelSelectorButtonWidthWithEndPadding() - mModelSelectorWidth);
         }
 
-        mNormalHelper.onSizeChanged(mWidth, mHeight, orientationChanged, LayoutManagerImpl.time());
+        mNormalHelper.onSizeChanged(
+                mWidth, getHeight(), orientationChanged, LayoutManagerImpl.time());
         mIncognitoHelper.onSizeChanged(
-                mWidth, mHeight, orientationChanged, LayoutManagerImpl.time());
+                mWidth, getHeight(), orientationChanged, LayoutManagerImpl.time());
 
         mStripFilterArea.set(0, 0, mWidth, Math.min(getHeight(), visibleViewportOffsetY));
         mEventFilter.setEventArea(mStripFilterArea);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSource.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSource.java
index 2342341..6cb9979 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSource.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSource.java
@@ -27,6 +27,7 @@
 
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.Log;
+import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
@@ -65,7 +66,7 @@
     private StripTabDragShadowView mShadowView;
     private PointF mDragShadowDefaultOffset = new PointF(0, 0);
     private float mPxToDp;
-    private final float mTabStripHeightPx;
+    private final ObservableSupplier<Integer> mTabStripHeightSupplier;
 
     /** Drag Event Listener trackers * */
     // Drag start screen position.
@@ -91,6 +92,7 @@
      * @param browserControlStateProvider @{@link BrowserControlsStateProvider} to compute
      *     drag-shadow dimens.
      * @param windowAndroid @{@link WindowAndroid} to access activity.
+     * @param tabStripHeightSupplier Supplier of the tab strip height.
      */
     public TabDragSource(
             @NonNull Context context,
@@ -100,10 +102,10 @@
             @NonNull MultiInstanceManager multiInstanceManager,
             @NonNull DragAndDropDelegate dragAndDropDelegate,
             @NonNull BrowserControlsStateProvider browserControlStateProvider,
-            @NonNull WindowAndroid windowAndroid) {
+            @NonNull WindowAndroid windowAndroid,
+            @NonNull ObservableSupplier<Integer> tabStripHeightSupplier) {
         mPxToDp = 1.f / context.getResources().getDisplayMetrics().density;
-        // TODO(crbug.com/1498252): Use Toolbar#getTabStripHeight() instead.
-        mTabStripHeightPx = context.getResources().getDimension(R.dimen.tab_strip_height);
+        mTabStripHeightSupplier = tabStripHeightSupplier;
         mStripLayoutHelperSupplier = stripLayoutHelperSupplier;
         mTabContentManagerSupplier = tabContentManagerSupplier;
         mLayerTitleCacheSupplier = layerTitleCacheSupplier;
@@ -231,7 +233,7 @@
     }
 
     private boolean didOccurInTabStrip(float yPx) {
-        return yPx <= mTabStripHeightPx;
+        return yPx <= mTabStripHeightSupplier.get();
     }
 
     private boolean onDragStart(float xPx, float yPx, ClipDescription clipDescription) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java
index fc60abec..7137f86 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java
@@ -351,6 +351,7 @@
                         mCompositorViewHolderSupplier.get() == null
                                 ? null
                                 : mCompositorViewHolderSupplier.get().getInMotionSupplier(),
+                        mWindowAndroid.getApplicationBottomInsetSupplier(),
                         this::isPageInsightsHubEnabled,
                         this::getPageInsightsConfig);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabBottomBarDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabBottomBarDelegate.java
index c626661..cdde6036 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabBottomBarDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabBottomBarDelegate.java
@@ -467,6 +467,9 @@
      */
     public void hideBottomBar(boolean hidesBottomBar) {
         if (hidesBottomBar) {
+            // No-op if it is already in hidden state. This keeps bottom controls height from
+            // changing inadvertently while it is being updated by other insets.
+            if (getBottomBarView().getVisibility() == View.GONE) return;
             getBottomBarView().setVisibility(View.GONE);
             mBrowserControlsSizer.setBottomControlsHeight(0, 0);
         } else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/device_dialog/UsbChooserDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/device_dialog/UsbChooserDialog.java
index 7bb24cc..e327388 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/device_dialog/UsbChooserDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/device_dialog/UsbChooserDialog.java
@@ -19,6 +19,7 @@
 import org.chromium.components.omnibox.OmniboxUrlEmphasizer;
 import org.chromium.components.permissions.ItemChooserDialog;
 import org.chromium.ui.base.WindowAndroid;
+import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.text.NoUnderlineClickableSpan;
 import org.chromium.ui.text.SpanApplier;
 import org.chromium.ui.text.SpanApplier.SpanInfo;
@@ -130,7 +131,8 @@
     }
 
     @CalledByNative
-    private static UsbChooserDialog create(
+    @VisibleForTesting
+    static UsbChooserDialog create(
             WindowAndroid windowAndroid,
             String origin,
             int securityLevel,
@@ -139,6 +141,18 @@
         Activity activity = windowAndroid.getActivity().get();
         if (activity == null) return null;
 
+        // Avoid showing the chooser when ModalDialogManager indicates that
+        // tab-modal or app-modal dialogs are suspended.
+        // TODO(crbug.com/1511004): Integrate UsbChooserDialog with
+        // ModalDialogManager.
+        ModalDialogManager modalDialogManager = windowAndroid.getModalDialogManager();
+        if (modalDialogManager != null
+                && (modalDialogManager.isSuspended(ModalDialogManager.ModalDialogType.TAB)
+                        || modalDialogManager.isSuspended(
+                                ModalDialogManager.ModalDialogType.APP))) {
+            return null;
+        }
+
         UsbChooserDialog dialog = new UsbChooserDialog(nativeUsbChooserDialogPtr, profile);
         dialog.show(activity, origin, securityLevel);
         return dialog;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageFactory.java
index 20db421..97d49200 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageFactory.java
@@ -65,6 +65,7 @@
     private final Supplier<Toolbar> mToolbarSupplier;
     private final HomeSurfaceTracker mHomeSurfaceTracker;
     private final ObservableSupplier<TabContentManager> mTabContentManagerSupplier;
+    private final ObservableSupplier<Integer> mTabStripHeightSupplier;
     private NewTabPageUma mNewTabPageUma;
 
     private NativePageBuilder mNativePageBuilder;
@@ -82,7 +83,8 @@
             @NonNull JankTracker jankTracker,
             @NonNull Supplier<Toolbar> toolbarSupplier,
             @Nullable HomeSurfaceTracker homeSurfaceTracker,
-            @Nullable ObservableSupplier<TabContentManager> tabContentManagerSupplier) {
+            @Nullable ObservableSupplier<TabContentManager> tabContentManagerSupplier,
+            @NonNull ObservableSupplier<Integer> tabStripHeightSupplier) {
         mActivity = activity;
         mBottomSheetController = sheetController;
         mBrowserControlsManager = browserControlsManager;
@@ -96,6 +98,7 @@
         mToolbarSupplier = toolbarSupplier;
         mHomeSurfaceTracker = homeSurfaceTracker;
         mTabContentManagerSupplier = tabContentManagerSupplier;
+        mTabStripHeightSupplier = tabStripHeightSupplier;
     }
 
     private NativePageBuilder getBuilder() {
@@ -115,7 +118,8 @@
                             mJankTracker,
                             mToolbarSupplier,
                             mHomeSurfaceTracker,
-                            mTabContentManagerSupplier);
+                            mTabContentManagerSupplier,
+                            mTabStripHeightSupplier);
         }
         return mNativePageBuilder;
     }
@@ -144,6 +148,7 @@
         private final Supplier<Toolbar> mToolbarSupplier;
         private final HomeSurfaceTracker mHomeSurfaceTracker;
         private final ObservableSupplier<TabContentManager> mTabContentManagerSupplier;
+        private final ObservableSupplier<Integer> mTabStripHeightSupplier;
 
         public NativePageBuilder(
                 Activity activity,
@@ -159,7 +164,8 @@
                 JankTracker jankTracker,
                 Supplier<Toolbar> toolbarSupplier,
                 HomeSurfaceTracker homeSurfaceTracker,
-                ObservableSupplier<TabContentManager> tabContentManagerSupplier) {
+                ObservableSupplier<TabContentManager> tabContentManagerSupplier,
+                ObservableSupplier<Integer> tabStripHeightSupplier) {
             mActivity = activity;
             mUma = uma;
             mBottomSheetController = sheetController;
@@ -174,6 +180,7 @@
             mToolbarSupplier = toolbarSupplier;
             mHomeSurfaceTracker = homeSurfaceTracker;
             mTabContentManagerSupplier = tabContentManagerSupplier;
+            mTabStripHeightSupplier = tabStripHeightSupplier;
         }
 
         protected NativePage buildNewTabPage(Tab tab, String url) {
@@ -200,7 +207,8 @@
                     mJankTracker,
                     mToolbarSupplier,
                     mHomeSurfaceTracker,
-                    mTabContentManagerSupplier);
+                    mTabContentManagerSupplier,
+                    mTabStripHeightSupplier);
         }
 
         protected NativePage buildBookmarksPage(Tab tab) {
@@ -247,7 +255,8 @@
                     mActivity,
                     recentTabsManager,
                     new TabShim(tab, mBrowserControlsManager, mTabModelSelector),
-                    mBrowserControlsManager);
+                    mBrowserControlsManager,
+                    mTabStripHeightSupplier);
         }
 
         protected NativePage buildManagementPage(Tab tab) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
index d993dc3..1f1edc3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
@@ -167,6 +167,7 @@
     private final TabModelSelector mTabModelSelector;
     private final TemplateUrlService mTemplateUrlService;
     private final ObservableSupplier<TabContentManager> mTabContentManagerSupplier;
+    private final ObservableSupplier<Integer> mTabStripHeightSupplier;
 
     private SingleTabSwitcherCoordinator mSingleTabSwitcherCoordinator;
     private ViewGroup mSingleTabCardContainer;
@@ -361,6 +362,7 @@
      * @param toolbarSupplier Supplies the {@link Toolbar}.
      * @param homeSurfaceTracker Used to decide whether we are the home surface.
      * @param tabContentManagerSupplier Used to create tab thumbnails.
+     * @param tabStripHeightSupplier Supplier for the tab strip height.
      */
     public NewTabPage(
             Activity activity,
@@ -381,7 +383,8 @@
             JankTracker jankTracker,
             Supplier<Toolbar> toolbarSupplier,
             HomeSurfaceTracker homeSurfaceTracker,
-            ObservableSupplier<TabContentManager> tabContentManagerSupplier) {
+            ObservableSupplier<TabContentManager> tabContentManagerSupplier,
+            ObservableSupplier<Integer> tabStripHeightSupplier) {
         mConstructedTimeNs = System.nanoTime();
         TraceEvent.begin(TAG);
 
@@ -398,6 +401,7 @@
         mHomeSurfaceTracker = homeSurfaceTracker;
         mTabContentManagerSupplier = tabContentManagerSupplier;
         mIsInNightMode = isInNightMode;
+        mTabStripHeightSupplier = tabStripHeightSupplier;
 
         Profile profile = mTab.getProfile();
 
@@ -560,7 +564,8 @@
                 isNtpAsHomeSurfaceOnTablet(),
                 mIsSurfacePolishEnabled,
                 mIsSurfacePolishOmniboxColorEnabled,
-                mIsTablet);
+                mIsTablet,
+                mTabStripHeightSupplier);
 
         // If new NewTabPage is created via back operations, re-show the single Tab card with the
         // previously tracked Tab.
@@ -636,7 +641,7 @@
                         /* viewportView= */ null,
                         actionDelegate,
                         HelpAndFeedbackLauncherImpl.getForProfile(profile),
-                        mTabModelSelector);
+                        mTabStripHeightSupplier);
         mFeedSurfaceProvider = feedSurfaceCoordinator;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
index 6379bba..ad751b7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
@@ -30,6 +30,7 @@
 import org.chromium.base.CallbackController;
 import org.chromium.base.MathUtils;
 import org.chromium.base.TraceEvent;
+import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.compositor.layouts.content.InvalidationAwareThumbnailProvider;
 import org.chromium.chrome.browser.feed.FeedSurfaceScrollDelegate;
@@ -157,6 +158,7 @@
     // order to make sure the animation is completed.
     private float mTransitionLengthOffset;
     private boolean mIsTablet;
+    private ObservableSupplier<Integer> mTabStripHeightSupplier;
 
     /** Constructor for inflating from XML. */
     public NewTabPageLayout(Context context, AttributeSet attrs) {
@@ -197,23 +199,25 @@
     /**
      * Initializes the NewTabPageLayout. This must be called immediately after inflation, before
      * this object is used in any other way.
-     * @param manager NewTabPageManager used to perform various actions when the user interacts
-     *                with the page.
+     *
+     * @param manager NewTabPageManager used to perform various actions when the user interacts with
+     *     the page.
      * @param activity The activity that currently owns the new tab page
      * @param tileGroupDelegate Delegate for {@link TileGroup}.
      * @param searchProviderHasLogo Whether the search provider has a logo.
      * @param searchProviderIsGoogle Whether the search provider is Google.
      * @param scrollDelegate The delegate used to obtain information about scroll state.
      * @param touchEnabledDelegate The {@link TouchEnabledDelegate} for handling whether touch
-     *         events are allowed.
+     *     events are allowed.
      * @param uiConfig UiConfig that provides display information about this view.
      * @param lifecycleDispatcher Activity lifecycle dispatcher.
      * @param uma {@link NewTabPageUma} object recording user metrics.
      * @param isIncognito Whether the new tab page is in incognito mode.
      * @param windowAndroid An instance of a {@link WindowAndroid}
      * @param isNtpAsHomeSurfaceOnTablet {@code true} if the NTP is showing as the home surface on
-     *         tablets.
+     *     tablets.
      * @param isSurfacePolishEnabled {@code true} if the NTP surface is polished.
+     * @param tabStripHeightSupplier Supplier of the tab strip height.
      */
     public void initialize(
             NewTabPageManager manager,
@@ -231,7 +235,8 @@
             boolean isNtpAsHomeSurfaceOnTablet,
             boolean isSurfacePolishEnabled,
             boolean isSurfacePolishOmniboxColorEnabled,
-            boolean isTablet) {
+            boolean isTablet,
+            ObservableSupplier<Integer> tabStripHeightSupplier) {
         TraceEvent.begin(TAG + ".initialize()");
         mScrollDelegate = scrollDelegate;
         mManager = manager;
@@ -245,6 +250,7 @@
         mIsSurfacePolishOmniboxColorEnabled = isSurfacePolishOmniboxColorEnabled;
         Profile profile = Profile.getLastUsedRegularProfile();
         mIsTablet = isTablet;
+        mTabStripHeightSupplier = tabStripHeightSupplier;
 
         if (mIsTablet) {
             mDisplayStyleObserver = this::onDisplayStyleChanged;
@@ -542,8 +548,8 @@
         final float transitionLength =
                 getResources().getDimensionPixelSize(R.dimen.ntp_search_box_transition_length)
                         + mTransitionLengthOffset;
-        // Tab strip height is zero on phones, nonzero on tablets.
-        int tabStripHeight = getResources().getDimensionPixelSize(R.dimen.tab_strip_height);
+        // Tab strip height is zero on phones, and may vary on tablets.
+        int tabStripHeight = mTabStripHeightSupplier.get();
 
         // |scrollY - searchBoxTop + tabStripHeight| gives the distance the search bar is from the
         // top of the tab.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsPage.java
index f5fc9d3b..28da55a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsPage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsPage.java
@@ -15,6 +15,8 @@
 import android.view.ViewGroup;
 import android.widget.ExpandableListView;
 
+import org.chromium.base.Callback;
+import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
 import org.chromium.chrome.browser.compositor.layouts.content.InvalidationAwareThumbnailProvider;
@@ -57,19 +59,25 @@
     /** Whether {@link #mView} is attached to the application window. */
     private boolean mIsAttachedToWindow;
 
+    private final ObservableSupplier<Integer> mTabStripHeightSupplier;
+    private final Callback<Integer> mTabStripHeightChangeCallback;
+
     /**
      * Constructor returns an instance of RecentTabsPage.
      *
      * @param activity The activity this view belongs to.
      * @param recentTabsManager The RecentTabsManager which provides the model data.
      * @param pageHost The NativePageHost used to provide a history navigation delegate object.
-     * @param browserControlsManager The BrowserControlsManager used to provide offset values.
+     * @param browserControlsStateProvider The {@link BrowserControlsStateProvider} used to provide
+     *     offset values.
+     * @param tabStripHeightSupplier Supplier for the tab strip height.
      */
     public RecentTabsPage(
             Activity activity,
             RecentTabsManager recentTabsManager,
             NativePageHost pageHost,
-            BrowserControlsStateProvider browserControlsStateProvider) {
+            BrowserControlsStateProvider browserControlsStateProvider,
+            ObservableSupplier<Integer> tabStripHeightSupplier) {
         mActivity = activity;
         mRecentTabsManager = recentTabsManager;
         mPageHost = pageHost;
@@ -100,6 +108,17 @@
             mBrowserControlsStateProvider = null;
         }
 
+        mTabStripHeightSupplier = tabStripHeightSupplier;
+        mView.setPadding(0, mTabStripHeightSupplier.get(), 0, 0);
+        mTabStripHeightChangeCallback =
+                newHeight ->
+                        mView.setPadding(
+                                mView.getPaddingLeft(),
+                                newHeight,
+                                mView.getPaddingRight(),
+                                mView.getPaddingBottom());
+        mTabStripHeightSupplier.addObserver(mTabStripHeightChangeCallback);
+
         onUpdated();
     }
 
@@ -149,6 +168,8 @@
         if (mBrowserControlsStateProvider != null) {
             mBrowserControlsStateProvider.removeObserver(this);
         }
+
+        mTabStripHeightSupplier.removeObserver(mTabStripHeightChangeCallback);
     }
 
     @Override
@@ -301,4 +322,8 @@
             recentTabsRoot.setLayoutParams(layoutParams);
         }
     }
+
+    Callback<Integer> getTabStripHeightChangeCallbackForTesting() {
+        return mTabStripHeightChangeCallback;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/GetPagesByNamespaceForLivePageSharingCallback.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/GetPagesByNamespaceForLivePageSharingCallback.java
deleted file mode 100644
index 6e3076cb..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/GetPagesByNamespaceForLivePageSharingCallback.java
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.offlinepages;
-
-import org.chromium.base.Callback;
-import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.components.browser_ui.share.ShareParams;
-
-import java.util.List;
-
-/**
- * This callback will take the items in the Live Page Sharing namespace and check if there is a page
- * matching the url of the given tab. If there is such page, share the page; otherwise save the page
- * and share.
- */
-public class GetPagesByNamespaceForLivePageSharingCallback
-        implements Callback<List<OfflinePageItem>> {
-    private Tab mTab;
-    private Callback<ShareParams> mShareCallback;
-    private OfflinePageBridge mBridge;
-
-    public GetPagesByNamespaceForLivePageSharingCallback(
-            Tab tab, final Callback<ShareParams> shareCallback, OfflinePageBridge bridge) {
-        mTab = tab;
-        mShareCallback = shareCallback;
-        mBridge = bridge;
-    }
-
-    @Override
-    public void onResult(List<OfflinePageItem> items) {
-        // If there is already a page in the Live Page Sharing namespace and matches the url, share
-        // it directly.
-        for (OfflinePageItem item : items) {
-            if (item.getUrl().equals(mTab.getUrl().getSpec())) {
-                OfflinePageUtils.sharePublishedPage(item, mTab.getWindowAndroid(), mShareCallback);
-                return;
-            }
-        }
-        // Otherwise, save the page within Live Page Sharing namespace and share it using content
-        // URI.
-        mBridge.savePage(
-                mTab.getWebContents(),
-                new ClientId(
-                        OfflinePageBridge.LIVE_PAGE_SHARING_NAMESPACE,
-                        Integer.toString(mTab.getId())),
-                new SavePageAndShareCallback(mTab.getWindowAndroid(), mShareCallback, mBridge));
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java
index 602b661..d9dfd1618 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java
@@ -11,7 +11,6 @@
 import android.os.Environment;
 import android.text.TextUtils;
 
-import androidx.annotation.IntDef;
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.ActivityState;
@@ -26,13 +25,9 @@
 import org.chromium.base.task.TaskTraits;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.FileProviderHelper;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.SadTab;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.tab.TabCreationState;
-import org.chromium.chrome.browser.tab.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabModelObserver;
 import org.chromium.chrome.browser.ui.messages.snackbar.Snackbar;
@@ -49,11 +44,8 @@
 import org.chromium.net.NetworkChangeNotifier;
 import org.chromium.ui.base.PageTransition;
 import org.chromium.ui.base.WindowAndroid;
-import org.chromium.url.GURL;
 
 import java.io.File;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -65,16 +57,6 @@
 
     private static final int DEFAULT_SNACKBAR_DURATION_MS = 6 * 1000; // 6 second
 
-    /**
-     * Bit flags to be OR-ed together to build the context of a tab restore to be used to identify
-     * the appropriate TabRestoreType in a lookup table.
-     */
-    private static final int BIT_ONLINE = 1;
-
-    private static final int BIT_CANT_SAVE_OFFLINE = 1 << 2;
-    private static final int BIT_OFFLINE_PAGE = 1 << 3;
-    private static final int BIT_LAST_N = 1 << 4;
-
     // Used instead of the constant so tests can override the value.
     private static int sSnackbarDurationMs = DEFAULT_SNACKBAR_DURATION_MS;
 
@@ -200,39 +182,6 @@
         }
     }
 
-    /**
-     * Contains values from the histogram enum OfflinePagesTabRestoreType used for reporting the
-     * OfflinePages.TabRestore metric.
-     */
-    @IntDef({
-        TabRestoreType.WHILE_ONLINE,
-        TabRestoreType.WHILE_ONLINE_CANT_SAVE_FOR_OFFLINE_USAGE,
-        TabRestoreType.WHILE_ONLINE_TO_OFFLINE_PAGE,
-        TabRestoreType.WHILE_ONLINE_TO_OFFLINE_PAGE_FROM_LAST_N,
-        TabRestoreType.WHILE_OFFLINE,
-        TabRestoreType.WHILE_OFFLINE_CANT_SAVE_FOR_OFFLINE_USAGE,
-        TabRestoreType.WHILE_OFFLINE_TO_OFFLINE_PAGE,
-        TabRestoreType.WHILE_OFFLINE_TO_OFFLINE_PAGE_FROM_LAST_N,
-        TabRestoreType.FAILED,
-        TabRestoreType.CRASHED
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    private @interface TabRestoreType {
-        int WHILE_ONLINE = 0;
-        int WHILE_ONLINE_CANT_SAVE_FOR_OFFLINE_USAGE = 1;
-        int WHILE_ONLINE_TO_OFFLINE_PAGE = 2;
-        int WHILE_ONLINE_TO_OFFLINE_PAGE_FROM_LAST_N = 3;
-        int WHILE_OFFLINE = 4;
-        int WHILE_OFFLINE_CANT_SAVE_FOR_OFFLINE_USAGE = 5;
-        int WHILE_OFFLINE_TO_OFFLINE_PAGE = 6;
-        int WHILE_OFFLINE_TO_OFFLINE_PAGE_FROM_LAST_N = 7;
-        int FAILED = 8;
-        int CRASHED = 9;
-        // NOTE: always keep this entry at the end. Add new result types only immediately above this
-        // line. Make sure to update the corresponding histogram enum accordingly.
-        int NUM_ENTRIES = 10;
-    }
-
     private static Internal getInstance() {
         if (sInstance == null) {
             sInstance = new OfflinePageUtilsImpl();
@@ -308,12 +257,6 @@
         OfflinePageTabObserver.addObserverForTab(tab);
     }
 
-    protected void showReloadSnackbarInternal(
-            Context context,
-            SnackbarManager snackbarManager,
-            final SnackbarController snackbarController,
-            int tabId) {}
-
     /**
      * Shows the "reload" snackbar for the given tab.
      * @param context The application context.
@@ -329,34 +272,6 @@
         getInstance().showReloadSnackbar(context, snackbarManager, snackbarController, tabId);
     }
 
-    /**
-     * Save the page loaded in current tab and share the saved page.
-     * @param tab The current tab from which the page is being shared.
-     * @param shareCallback The callback to be used to send the ShareParams. This will only be
-     *                      called if this function call returns true.
-     * @return true if the sharing of the page is possible. The callback will be invoked if
-     *                      saving the page succeeds.
-     */
-    public static boolean saveAndSharePage(Tab tab, final Callback<ShareParams> shareCallback) {
-        OfflinePageBridge offlinePageBridge = getInstance().getOfflinePageBridge(tab.getProfile());
-
-        if (offlinePageBridge == null) {
-            Log.e(TAG, "Unable to share current tab as an offline page.");
-            return false;
-        }
-
-        WebContents webContents = tab.getWebContents();
-        if (webContents == null) return false;
-
-        GetPagesByNamespaceForLivePageSharingCallback callback =
-                new GetPagesByNamespaceForLivePageSharingCallback(
-                        tab, shareCallback, offlinePageBridge);
-        offlinePageBridge.getPagesByNamespace(
-                OfflinePageBridge.LIVE_PAGE_SHARING_NAMESPACE, callback);
-
-        return true;
-    }
-
     private static void getOfflinePageUriForSharing(
             String tabUrl,
             boolean isPageTemporary,
@@ -400,27 +315,11 @@
      *                      afterwards via PostTask.
      */
     public static void maybeShareOfflinePage(Tab tab, final Callback<ShareParams> shareCallback) {
-        if (tab == null || !tab.isInitialized()) {
+        if (tab == null || !tab.isInitialized() || !OfflinePageUtils.isOfflinePage(tab)) {
             shareCallback.onResult(null);
             return;
         }
 
-        boolean isOfflinePage = OfflinePageUtils.isOfflinePage(tab);
-
-        // If the current tab is not showing an offline page, try to see if we should do live page
-        // sharing.
-        if (!isOfflinePage) {
-            if (ChromeFeatureList.isEnabled(ChromeFeatureList.OFFLINE_PAGES_LIVE_PAGE_SHARING)) {
-                if (!saveAndSharePage(tab, shareCallback)) {
-                    shareCallback.onResult(null);
-                }
-                return;
-            } else {
-                shareCallback.onResult(null);
-                return;
-            }
-        }
-
         OfflinePageBridge offlinePageBridge = getInstance().getOfflinePageBridge(tab.getProfile());
 
         if (offlinePageBridge == null) {
@@ -831,7 +730,6 @@
      */
     private static class RecentTabTracker extends TabModelSelectorTabModelObserver {
         /** The single, stateless TabRestoreTracker instance to monitor all tab restores. */
-        private static final TabRestoreTracker sTabRestoreTracker = new TabRestoreTracker();
 
         private TabModelSelector mTabModelSelector;
 
@@ -841,15 +739,6 @@
         }
 
         @Override
-        public void didAddTab(
-                Tab tab,
-                @TabLaunchType int type,
-                @TabCreationState int creationState,
-                boolean markedForSelection) {
-            tab.addObserver(sTabRestoreTracker);
-        }
-
-        @Override
         public void willCloseTab(Tab tab, boolean animate, boolean didCloseAlone) {
             Profile profile = mTabModelSelector.getModel(tab.isIncognito()).getProfile();
             OfflinePageBridge bridge = OfflinePageBridge.getForProfile(profile);
@@ -910,62 +799,6 @@
         }
     }
 
-    private static class TabRestoreTracker extends EmptyTabObserver {
-        /**
-         * If the tab was being restored, reports that it successfully finished reloading its
-         * contents.
-         */
-        @Override
-        public void onPageLoadFinished(Tab tab, GURL url) {
-            if (!tab.isBeingRestored()) return;
-
-            // We first compute the bitwise tab restore context.
-            int tabRestoreContext = 0;
-            if (isConnected()) tabRestoreContext |= BIT_ONLINE;
-            OfflinePageItem page = getOfflinePage(tab.getWebContents());
-            if (page != null) {
-                tabRestoreContext |= BIT_OFFLINE_PAGE;
-                if (page.getClientId().getNamespace().equals(OfflinePageBridge.LAST_N_NAMESPACE)) {
-                    tabRestoreContext |= BIT_LAST_N;
-                }
-            } else if (!OfflinePageBridge.canSavePage(tab.getUrl()) || tab.isIncognito()) {
-                tabRestoreContext |= BIT_CANT_SAVE_OFFLINE;
-            }
-
-            // Now determine the correct tab restore type based on the context.
-            int tabRestoreType;
-            switch (tabRestoreContext) {
-                case BIT_ONLINE:
-                    tabRestoreType = TabRestoreType.WHILE_ONLINE;
-                    break;
-                case BIT_ONLINE | BIT_CANT_SAVE_OFFLINE:
-                    tabRestoreType = TabRestoreType.WHILE_ONLINE_CANT_SAVE_FOR_OFFLINE_USAGE;
-                    break;
-                case BIT_ONLINE | BIT_OFFLINE_PAGE:
-                    tabRestoreType = TabRestoreType.WHILE_ONLINE_TO_OFFLINE_PAGE;
-                    break;
-                case BIT_ONLINE | BIT_OFFLINE_PAGE | BIT_LAST_N:
-                    tabRestoreType = TabRestoreType.WHILE_ONLINE_TO_OFFLINE_PAGE_FROM_LAST_N;
-                    break;
-                case 0: // offline (not BIT_ONLINE present).
-                    tabRestoreType = TabRestoreType.WHILE_OFFLINE;
-                    break;
-                case BIT_CANT_SAVE_OFFLINE:
-                    tabRestoreType = TabRestoreType.WHILE_OFFLINE_CANT_SAVE_FOR_OFFLINE_USAGE;
-                    break;
-                case BIT_OFFLINE_PAGE:
-                    tabRestoreType = TabRestoreType.WHILE_OFFLINE_TO_OFFLINE_PAGE;
-                    break;
-                case BIT_OFFLINE_PAGE | BIT_LAST_N:
-                    tabRestoreType = TabRestoreType.WHILE_OFFLINE_TO_OFFLINE_PAGE_FROM_LAST_N;
-                    break;
-                default:
-                    assert false;
-                    return;
-            }
-        }
-    }
-
     public static void setInstanceForTesting(Internal instance) {
         var oldValue = sInstance;
         sInstance = instance;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/SavePageAndShareCallback.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/SavePageAndShareCallback.java
deleted file mode 100644
index d6de268..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/SavePageAndShareCallback.java
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.offlinepages;
-
-import org.chromium.base.Callback;
-import org.chromium.components.browser_ui.share.ShareParams;
-import org.chromium.components.offlinepages.SavePageResult;
-import org.chromium.ui.base.WindowAndroid;
-
-/**
- * This callback will save get the saved page during live page sharing and share the page if saving
- * process succeeds.
- */
-public class SavePageAndShareCallback implements OfflinePageBridge.SavePageCallback {
-    private WindowAndroid mWindow;
-    private Callback<ShareParams> mShareCallback;
-    private OfflinePageBridge mBridge;
-
-    public SavePageAndShareCallback(
-            WindowAndroid window,
-            final Callback<ShareParams> shareCallback,
-            OfflinePageBridge bridge) {
-        mWindow = window;
-        mShareCallback = shareCallback;
-        mBridge = bridge;
-    }
-
-    @Override
-    public void onSavePageDone(int savePageResult, String url, long offlineId) {
-        if (savePageResult != SavePageResult.SUCCESS) {
-            // If the page is not saved, skip the sharing part.
-            return;
-        }
-        mBridge.getPageByOfflineId(
-                offlineId,
-                new Callback<OfflinePageItem>() {
-                    @Override
-                    public void onResult(OfflinePageItem page) {
-                        OfflinePageUtils.sharePublishedPage(page, mWindow, mShareCallback);
-                    }
-                });
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index 8e1d6f1..73a7b7a9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -751,8 +751,11 @@
                         mConstraintsProxy);
         mTabStripHeightSupplier.set(mToolbar.getTabStripHeight());
         mActionModeController =
-                new ActionModeController(mActivity, mActionBarDelegate, toolbarActionModeCallback);
-        mActionModeController.setTabStripHeight(mToolbar.getTabStripHeight());
+                new ActionModeController(
+                        mActivity,
+                        mActionBarDelegate,
+                        toolbarActionModeCallback,
+                        mTabStripHeightSupplier);
 
         tabObscuringHandler.addObserver(this);
 
@@ -859,7 +862,8 @@
                         /* context= */ activity,
                         mLocationBarModel,
                         clickDelegate,
-                        scrimTarget);
+                        scrimTarget,
+                        mTabStripHeightSupplier);
 
         var omnibox = mLocationBar.getOmniboxStub();
         if (omnibox != null) {
@@ -1989,6 +1993,7 @@
 
         mControlContainer.destroy();
         mConstraintsProxy.destroy();
+        mLocationBarFocusHandler.destroy();
     }
 
     /** Called when the orientation of the activity has changed. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstallBroadcastReceiver.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstallBroadcastReceiver.java
index 2c10b7b..2d8e29eb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstallBroadcastReceiver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstallBroadcastReceiver.java
@@ -4,22 +4,14 @@
 
 package org.chromium.chrome.browser.webapps;
 
-import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
 import android.net.Uri;
-import android.service.notification.StatusBarNotification;
-
-import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.IntentUtils;
 import org.chromium.chrome.browser.browserservices.intents.WebappConstants;
-import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
 import org.chromium.components.browser_ui.notifications.PendingIntentProvider;
 
 /**
@@ -33,24 +25,14 @@
 public class WebApkInstallBroadcastReceiver extends BroadcastReceiver {
     private static final String TAG = "webapk";
 
-    static final String ACTION_RETRY_INSTALL = "WebApkInstallNotification.retry";
     static final String ACTION_OPEN_IN_BROWSER = "WebApkInstallNotification.open";
 
     private static final String NOTIFICATION_ID = "WebApkInstallNotification.notification_id";
     private static final String WEBAPK_START_URL = "WebApkInstallNotification.start_url";
-    @VisibleForTesting static final String RETRY_PROTO = "WebApkInstallNotification.retry_proto";
-
-    private WebApkInstallCoordinatorBridge mBridge;
 
     /** Constructor used by the Android framework. */
     public WebApkInstallBroadcastReceiver() {}
 
-    /** Constructor that allows dependency injection for use in tests. */
-    @VisibleForTesting
-    public WebApkInstallBroadcastReceiver(WebApkInstallCoordinatorBridge bridge) {
-        mBridge = bridge;
-    }
-
     @Override
     public void onReceive(Context context, Intent intent) {
         assert intent != null && intent.hasExtra(NOTIFICATION_ID);
@@ -58,49 +40,19 @@
         String id = IntentUtils.safeGetStringExtra(intent, NOTIFICATION_ID);
         String startUrl = IntentUtils.safeGetStringExtra(intent, WEBAPK_START_URL);
 
-        byte[] proto = IntentUtils.safeGetByteArrayExtra(intent, RETRY_PROTO);
-        Bitmap icon = getCurrentIconFromNotification(context, id);
-
         WebApkInstallService.cancelNotification(id);
 
-        if (ACTION_RETRY_INSTALL.equals(intent.getAction())) {
-            if (icon != null && proto != null && proto.length != 0) {
-                retryInstall(id, proto, icon);
-            } else {
-                assert false : "Invalid intent data " + id;
-                openInChrome(context, startUrl);
-            }
-        } else if (ACTION_OPEN_IN_BROWSER.equals(intent.getAction())) {
+        if (ACTION_OPEN_IN_BROWSER.equals(intent.getAction())) {
             openInChrome(context, startUrl);
         }
     }
 
-    // Get the Bitmap icon from the current install notification, it will be use for the retry
-    // install notification.
-    private @Nullable Bitmap getCurrentIconFromNotification(Context context, String id) {
-        NotificationManager nm =
-                (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
-        for (StatusBarNotification sbn : nm.getActiveNotifications()) {
-            if ((WebApkInstallService.WEBAPK_INSTALL_NOTIFICATION_TAG_PREFIX + id)
-                    .equals(sbn.getTag())) {
-                return ((BitmapDrawable) sbn.getNotification().getLargeIcon().loadDrawable(context))
-                        .getBitmap();
-            }
-        }
-        return null;
-    }
-
     static PendingIntentProvider createPendingIntent(
-            Context context,
-            String notificationId,
-            String url,
-            String action,
-            byte[] serializedProto) {
+            Context context, String notificationId, String url, String action) {
         Intent intent = new Intent(action);
         intent.setClass(context, WebApkInstallBroadcastReceiver.class);
         intent.putExtra(NOTIFICATION_ID, notificationId);
         intent.putExtra(WEBAPK_START_URL, url);
-        intent.putExtra(RETRY_PROTO, serializedProto);
 
         int requestCode = 0;
         int flags = PendingIntent.FLAG_UPDATE_CURRENT;
@@ -114,12 +66,4 @@
         chromeIntent.putExtra(WebappConstants.REUSE_URL_MATCHING_TAB_ELSE_NEW_TAB, true);
         context.startActivity(chromeIntent);
     }
-
-    private void retryInstall(String id, byte[] proto, Bitmap icon) {
-        if (mBridge == null) {
-            ChromeBrowserInitializer.getInstance().handleSynchronousStartup();
-            mBridge = new WebApkInstallCoordinatorBridge();
-        }
-        mBridge.retry(id, proto, icon);
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstallCoordinatorBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstallCoordinatorBridge.java
deleted file mode 100644
index 40eec218..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstallCoordinatorBridge.java
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.webapps;
-
-import android.graphics.Bitmap;
-import android.os.RemoteException;
-
-import androidx.annotation.BinderThread;
-
-import org.jni_zero.CalledByNative;
-import org.jni_zero.JNINamespace;
-import org.jni_zero.NativeMethods;
-
-import org.chromium.components.webapk_install.IOnFinishInstallCallback;
-
-/**
- * This class owns the native WebApkInstallCoordinatorBridge, so {@link destroy} must be
- * called from Java side to avoid memory leaks.
- * The C++ counterpart of this class handles the WebAPK installation and calls
- * {@link onFinishedInstall} which is invoking the {@code callback} with the outcome
- * of the installation.
- */
-@JNINamespace("webapps")
-public class WebApkInstallCoordinatorBridge {
-    private long mNativeWebApkInstallCoordinatorBridge;
-    private IOnFinishInstallCallback mCallback;
-
-    public WebApkInstallCoordinatorBridge() {
-        mNativeWebApkInstallCoordinatorBridge =
-                WebApkInstallCoordinatorBridgeJni.get().init(WebApkInstallCoordinatorBridge.this);
-    }
-
-    @BinderThread
-    void install(
-            byte[] apkProto,
-            Bitmap primaryIcon,
-            boolean isPrimaryIconMaskable,
-            IOnFinishInstallCallback callback) {
-        mCallback = callback;
-
-        WebApkInstallCoordinatorBridgeJni.get()
-                .install(
-                        mNativeWebApkInstallCoordinatorBridge,
-                        WebApkInstallCoordinatorBridge.this,
-                        apkProto,
-                        primaryIcon,
-                        isPrimaryIconMaskable);
-    }
-
-    @CalledByNative
-    @BinderThread
-    void onFinishedInstall(int result) {
-        try {
-            mCallback.handleOnFinishInstall(result);
-        } catch (RemoteException e) {
-            // Client shut down already, nothing to do.
-        }
-        destroy();
-    }
-
-    // Must be called to destroy this and the native counterpart. Called by the
-    // {@link onFinishedInstall} callback that is invoked by the {@link WebApkInstaller}
-    // when the installation finished or failed.
-    @BinderThread
-    void destroy() {
-        if (mNativeWebApkInstallCoordinatorBridge != 0) {
-            WebApkInstallCoordinatorBridgeJni.get().destroy(mNativeWebApkInstallCoordinatorBridge);
-            mNativeWebApkInstallCoordinatorBridge = 0;
-        }
-    }
-
-    void retry(String startUrl, byte[] proto, Bitmap primaryIcon) {
-        WebApkInstallCoordinatorBridgeJni.get()
-                .retry(mNativeWebApkInstallCoordinatorBridge, startUrl, proto, primaryIcon);
-    }
-
-    @NativeMethods
-    interface Natives {
-        long init(WebApkInstallCoordinatorBridge caller);
-
-        void install(
-                long nativeWebApkInstallCoordinatorBridge,
-                WebApkInstallCoordinatorBridge caller,
-                byte[] apkProto,
-                Bitmap primaryIcon,
-                boolean isPrimaryIconMaskable);
-
-        void retry(
-                long nativeWebApkInstallCoordinatorBridge,
-                String startUrl,
-                byte[] apkProto,
-                Bitmap primaryIcon);
-
-        void destroy(long nativeWebApkInstallCoordinatorBridge);
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstallCoordinatorService.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstallCoordinatorService.java
deleted file mode 100644
index 7452706..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstallCoordinatorService.java
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.webapps;
-
-import org.chromium.build.annotations.IdentifierNameString;
-import org.chromium.chrome.browser.base.SplitCompatService;
-
-/** See {@link WebApkInstallCoordinatorServiceImpl}. */
-public class WebApkInstallCoordinatorService extends SplitCompatService {
-    private static @IdentifierNameString String sImplClassName =
-            "org.chromium.chrome.browser.webapps.WebApkInstallCoordinatorServiceImpl";
-
-    public WebApkInstallCoordinatorService() {
-        super(sImplClassName);
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstallCoordinatorServiceImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstallCoordinatorServiceImpl.java
deleted file mode 100644
index 4ed8fbd..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstallCoordinatorServiceImpl.java
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.webapps;
-
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.os.IBinder;
-
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
-import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
-import org.chromium.components.version_info.VersionInfo;
-import org.chromium.components.webapk_install.IOnFinishInstallCallback;
-import org.chromium.components.webapk_install.IWebApkInstallCoordinatorService;
-
-/**
- * Android service that is used to schedule WebAPK installs from Weblayer.
- * The service is currently hidden behind a FeatureFlag.
- */
-public class WebApkInstallCoordinatorServiceImpl extends WebApkInstallCoordinatorService.Impl {
-    private final IWebApkInstallCoordinatorService.Stub mBinder =
-            new IWebApkInstallCoordinatorService.Stub() {
-                @Override
-                public void scheduleInstallAsync(
-                        byte[] apkProto,
-                        Bitmap primaryIcon,
-                        boolean isPrimaryIconMaskable,
-                        IOnFinishInstallCallback callback) {
-                    WebApkInstallCoordinatorBridge bridge = new WebApkInstallCoordinatorBridge();
-                    bridge.install(apkProto, primaryIcon, isPrimaryIconMaskable, callback);
-                }
-            };
-
-    @Override
-    public void onCreate() {
-        ChromeBrowserInitializer.getInstance().handleSynchronousStartup();
-        super.onCreate();
-    }
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        if (ChromeFeatureList.isEnabled(ChromeFeatureList.WEB_APK_INSTALL_SERVICE)
-                && VersionInfo.isLocalBuild()) {
-            return mBinder;
-        }
-        return null;
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstallService.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstallService.java
index 0bf31b0..cec456c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstallService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstallService.java
@@ -16,7 +16,6 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.notifications.NotificationUmaTracker;
 import org.chromium.chrome.browser.notifications.NotificationUmaTracker.SystemNotificationType;
 import org.chromium.chrome.browser.notifications.NotificationWrapperBuilderFactory;
@@ -73,8 +72,7 @@
                 url,
                 icon,
                 context.getResources().getString(R.string.notification_webapk_installed),
-                clickPendingIntent,
-                null);
+                clickPendingIntent);
     }
 
     /** Display a notification when an install starts. */
@@ -100,7 +98,6 @@
                 url,
                 icon,
                 message,
-                null,
                 null);
         WebappsUtils.showToast(message);
     }
@@ -114,8 +111,7 @@
             String url,
             Bitmap icon,
             boolean isIconMaskable,
-            @WebApkInstallResult int resultCode,
-            byte[] serializedProto) {
+            @WebApkInstallResult int resultCode) {
         Context context = ContextUtils.getApplicationContext();
         String titleMessage =
                 context.getResources()
@@ -127,21 +123,7 @@
                         context,
                         notificationId,
                         url,
-                        WebApkInstallBroadcastReceiver.ACTION_OPEN_IN_BROWSER,
-                        null);
-        PendingIntentProvider retryIntent = null;
-        if (canRetryFailedInstall(resultCode)
-                && serializedProto != null
-                && serializedProto.length > 0) {
-            retryIntent =
-                    WebApkInstallBroadcastReceiver.createPendingIntent(
-                            context,
-                            notificationId,
-                            url,
-                            WebApkInstallBroadcastReceiver.ACTION_RETRY_INSTALL,
-                            serializedProto);
-        }
-
+                        WebApkInstallBroadcastReceiver.ACTION_OPEN_IN_BROWSER);
         if (isIconMaskable && WebappsIconUtils.doesAndroidSupportMaskableIcons()) {
             icon = WebappsIconUtils.generateAdaptiveIconBitmap(icon);
         }
@@ -152,8 +134,7 @@
                 url,
                 icon,
                 contentMessage,
-                openUrlIntent,
-                retryIntent);
+                openUrlIntent);
     }
 
     private static void showNotification(
@@ -163,8 +144,7 @@
             String url,
             Bitmap icon,
             String message,
-            PendingIntentProvider clickPendingIntent,
-            PendingIntentProvider retryIntent) {
+            PendingIntentProvider clickPendingIntent) {
         Context context = ContextUtils.getApplicationContext();
 
         String channelId;
@@ -198,15 +178,6 @@
                 .setAutoCancel(true);
 
         if (type == SystemNotificationType.WEBAPK_INSTALL_FAILED) {
-            if (ChromeFeatureList.isEnabled(ChromeFeatureList.WEB_APK_INSTALL_RETRY)
-                    && retryIntent != null) {
-                notificationBuilder.addAction(
-                        0 /* no icon */,
-                        context.getResources()
-                                .getString(R.string.webapk_install_failed_action_retry),
-                        retryIntent,
-                        NotificationUmaTracker.ActionType.WEB_APK_ACTION_RETRY);
-            }
             notificationBuilder.addAction(
                     0 /* no icon */,
                     context.getResources().getString(R.string.webapk_install_failed_action_open),
@@ -229,18 +200,6 @@
         notificationManager.cancel(getInstallNotificationTag(notificationId), PLATFORM_ID);
     }
 
-    private static boolean canRetryFailedInstall(@WebApkInstallResult int resultCode) {
-        switch (resultCode) {
-            case WebApkInstallResult.FAILURE:
-            case WebApkInstallResult.SERVER_ERROR:
-            case WebApkInstallResult.REQUEST_TIMEOUT:
-            case WebApkInstallResult.NOT_ENOUGH_SPACE:
-                return true;
-            default:
-                return false;
-        }
-    }
-
     private static String getInstallErrorMessage(@WebApkInstallResult int resultCode) {
         String message;
         if (resultCode == WebApkInstallResult.NOT_ENOUGH_SPACE) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/DetachedResourceRequestTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/DetachedResourceRequestTest.java
index bca31822..471f175 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/DetachedResourceRequestTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/DetachedResourceRequestTest.java
@@ -113,7 +113,6 @@
 
     @Test
     @SmallTest
-    @EnableFeatures(ChromeFeatureList.CCT_RESOURCE_PREFETCH)
     public void testCanDoResourcePrefetch() throws Exception {
         CustomTabsSessionToken session = CustomTabsSessionToken.createMockSessionTokenForTesting();
         Assert.assertTrue(mConnection.newSession(session));
@@ -208,7 +207,6 @@
 
     @Test
     @SmallTest
-    @EnableFeatures(ChromeFeatureList.CCT_RESOURCE_PREFETCH)
     public void testStartResourcePrefetchUrlsValidation() throws Exception {
         CustomTabsSessionToken session = prepareSession();
         CustomTabsTestUtils.warmUpAndWait();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/device_dialog/BluetoothChooserDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/device_dialog/BluetoothChooserDialogTest.java
index 92e005a..a6e399f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/device_dialog/BluetoothChooserDialogTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/device_dialog/BluetoothChooserDialogTest.java
@@ -4,7 +4,11 @@
 
 package org.chromium.chrome.browser.device_dialog;
 
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
 import android.Manifest;
+import android.app.Activity;
 import android.app.Dialog;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -24,6 +28,7 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
 
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CommandLineFlags;
@@ -47,10 +52,13 @@
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.content_public.browser.test.util.TouchCommon;
 import org.chromium.ui.base.ActivityWindowAndroid;
+import org.chromium.ui.base.WindowAndroid;
+import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.permissions.AndroidPermissionDelegate;
 import org.chromium.ui.permissions.PermissionCallback;
 import org.chromium.ui.widget.TextViewWithClickableSpans;
 
+import java.lang.ref.WeakReference;
 import java.util.Arrays;
 import java.util.concurrent.Callable;
 
@@ -83,6 +91,11 @@
     private String mFinishedDeviceId;
     private int mRestartSearchCount;
 
+    // Unused member variables to avoid Java optimizer issues with Mockito.
+    @Mock ModalDialogManager mMockModalDialogManager;
+    @Mock Activity mMockActivity;
+    @Mock WindowAndroid mMockWindowAndroid;
+
     private class TestBluetoothChooserDialogJni implements BluetoothChooserDialog.Natives {
         private BluetoothChooserDialog mBluetoothChooserDialog;
 
@@ -590,6 +603,38 @@
         mChooserDialog.closeDialog();
     }
 
+    @Test
+    @SmallTest
+    public void testChooserBlockedByModalDialogManager() {
+        ModalDialogManager mockModalDialogManager = mock(ModalDialogManager.class);
+        when(mockModalDialogManager.isSuspended(ModalDialogManager.ModalDialogType.APP))
+                .thenReturn(true);
+        when(mockModalDialogManager.isSuspended(ModalDialogManager.ModalDialogType.TAB))
+                .thenReturn(true);
+        Activity mockActivity = mock(Activity.class);
+        WindowAndroid mockWindowAndroid = mock(WindowAndroid.class);
+        when(mockWindowAndroid.getActivity()).thenReturn(new WeakReference<>(mockActivity));
+        when(mockWindowAndroid.getModalDialogManager()).thenReturn(mockModalDialogManager);
+        when(mockWindowAndroid.hasPermission(Manifest.permission.BLUETOOTH_SCAN)).thenReturn(true);
+        when(mockWindowAndroid.hasPermission(Manifest.permission.BLUETOOTH_CONNECT))
+                .thenReturn(true);
+        when(mockWindowAndroid.hasPermission(Manifest.permission.ACCESS_FINE_LOCATION))
+                .thenReturn(true);
+
+        BluetoothChooserDialog dialog;
+        dialog =
+                TestThreadUtils.runOnUiThreadBlockingNoException(
+                        () -> {
+                            return BluetoothChooserDialog.create(
+                                    mockWindowAndroid,
+                                    "https://origin.example.com/",
+                                    ConnectionSecurityLevel.SECURE,
+                                    /* delegate= */ null,
+                                    /* nativeUsbChooserDialogPtr= */ 42);
+                        });
+        Assert.assertNull(dialog);
+    }
+
     private static class TestAndroidPermissionDelegate implements AndroidPermissionDelegate {
         Dialog mDialog;
         PermissionCallback mCallback;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/device_dialog/UsbChooserDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/device_dialog/UsbChooserDialogTest.java
index b1ebe7b..deeb6858 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/device_dialog/UsbChooserDialogTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/device_dialog/UsbChooserDialogTest.java
@@ -4,6 +4,10 @@
 
 package org.chromium.chrome.browser.device_dialog;
 
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
 import android.app.Dialog;
 import android.view.View;
 import android.widget.Button;
@@ -18,6 +22,7 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
 
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CommandLineFlags;
@@ -33,8 +38,12 @@
 import org.chromium.components.security_state.ConnectionSecurityLevel;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.content_public.browser.test.util.TouchCommon;
+import org.chromium.ui.base.WindowAndroid;
+import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.widget.TextViewWithClickableSpans;
 
+import java.lang.ref.WeakReference;
+
 /** Tests for the UsbChooserDialog class. */
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
@@ -54,6 +63,11 @@
 
     private UsbChooserDialog mChooserDialog;
 
+    // Unused member variables to avoid Java optimizer issues with Mockito.
+    @Mock ModalDialogManager mMockModalDialogManager;
+    @Mock Activity mMockActivity;
+    @Mock WindowAndroid mMockWindowAndroid;
+
     private class TestUsbChooserDialogJni implements UsbChooserDialog.Natives {
         @Override
         public void onItemSelected(long nativeUsbChooserDialogAndroid, String deviceId) {
@@ -182,4 +196,31 @@
 
         Assert.assertEquals("device_id_1", mSelectedDeviceId);
     }
+
+    @Test
+    @SmallTest
+    public void testChooserBlockedByModalDialogManager() {
+        ModalDialogManager mockModalDialogManager = mock(ModalDialogManager.class);
+        when(mockModalDialogManager.isSuspended(ModalDialogManager.ModalDialogType.APP))
+                .thenReturn(true);
+        when(mockModalDialogManager.isSuspended(ModalDialogManager.ModalDialogType.TAB))
+                .thenReturn(true);
+        Activity mockActivity = mock(Activity.class);
+        WindowAndroid mockWindowAndroid = mock(WindowAndroid.class);
+        when(mockWindowAndroid.getActivity()).thenReturn(new WeakReference<>(mockActivity));
+        when(mockWindowAndroid.getModalDialogManager()).thenReturn(mockModalDialogManager);
+
+        UsbChooserDialog dialog;
+        dialog =
+                TestThreadUtils.runOnUiThreadBlockingNoException(
+                        () -> {
+                            return UsbChooserDialog.create(
+                                    mockWindowAndroid,
+                                    "https://origin.example.com/",
+                                    ConnectionSecurityLevel.SECURE,
+                                    Profile.getLastUsedRegularProfile(),
+                                    /* nativeUsbChooserDialogPtr= */ 42);
+                        });
+        Assert.assertNull(dialog);
+    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/RecentTabsPageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/RecentTabsPageTest.java
index bc1d61d..5652149 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/RecentTabsPageTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/RecentTabsPageTest.java
@@ -11,6 +11,7 @@
 import static androidx.test.espresso.matcher.ViewMatchers.withParent;
 
 import static org.hamcrest.core.AllOf.allOf;
+import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.MockitoAnnotations.initMocks;
@@ -20,6 +21,7 @@
 
 import androidx.test.filters.LargeTest;
 import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
 
 import org.hamcrest.Matchers;
 import org.junit.After;
@@ -332,6 +334,20 @@
                 .check(matches(isDisplayed()));
     }
 
+    @Test
+    @SmallTest
+    public void testTabStripHeightChangeCallback() {
+        mPage = loadRecentTabsPage();
+        var tabStripHeightChangeCallback = mPage.getTabStripHeightChangeCallbackForTesting();
+        int newTabStripHeight = 40;
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> tabStripHeightChangeCallback.onResult(newTabStripHeight));
+        assertEquals(
+                "Top padding of page view should be updated when tab strip height changes.",
+                newTabStripHeight,
+                mPage.getView().getPaddingTop());
+    }
+
     private CoreAccountInfo addAccountWithNonDisplayableEmail(String name) {
         CoreAccountInfo coreAccountInfo =
                 mSigninTestRule.addAccount(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabUmaTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabUmaTest.java
index 3593d2c1..2cc1f74 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabUmaTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabUmaTest.java
@@ -98,7 +98,8 @@
                 new PlaceholderJankTracker(),
                 rootUiCoordinator.getToolbarManager()::getToolbar,
                 null,
-                null);
+                null,
+                rootUiCoordinator.getToolbarManager().getTabStripHeightSupplier());
     }
 
     private Tab createLazilyLoadedTab(boolean show) throws ExecutionException {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManagerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManagerTest.java
index fed8b55..0f4c087 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManagerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManagerTest.java
@@ -61,6 +61,7 @@
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelFilterProvider;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
+import org.chromium.chrome.browser.toolbar.top.Toolbar;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
 import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
@@ -96,10 +97,12 @@
     @Mock private ObservableSupplierImpl<TabContentManager> mTabContentManagerSupplier;
     @Mock private BrowserControlsStateProvider mBrowserControlStateProvider;
     @Mock private WindowAndroid mWindowAndroid;
+    @Mock private Toolbar mToolbar;
 
     private StripLayoutHelperManager mStripLayoutHelperManager;
     private Context mContext;
     private ObservableSupplierImpl<TabModelStartupInfo> mTabModelStartupInfoSupplier;
+    private ObservableSupplierImpl<Integer> mTabStripHeightSupplier;
     private static final float SCREEN_WIDTH = 800.f;
     private static final float SCREEN_HEIGHT = 1600.f;
     private static final float VISIBLE_VIEWPORT_Y = 200.f;
@@ -128,6 +131,12 @@
         when(mTabModelSelector.getTabModelFilterProvider()).thenReturn(mTabModelFilterProvider);
 
         mTabModelStartupInfoSupplier = new ObservableSupplierImpl<>();
+
+        var tabStripHeight =
+                mContext.getResources().getDimensionPixelSize(R.dimen.tab_strip_height);
+        mTabStripHeightSupplier = new ObservableSupplierImpl<>();
+        mTabStripHeightSupplier.set(tabStripHeight);
+
         mStripLayoutHelperManager =
                 new StripLayoutHelperManager(
                         mContext,
@@ -143,7 +152,8 @@
                         mTabHoverCardViewStub,
                         mTabContentManagerSupplier,
                         mBrowserControlStateProvider,
-                        mWindowAndroid);
+                        mWindowAndroid,
+                        mTabStripHeightSupplier);
         mStripLayoutHelperManager.setTabModelSelector(mTabModelSelector, mTabCreatorManager);
     }
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSourceTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSourceTest.java
index 13842a4..b657cd49f 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSourceTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSourceTest.java
@@ -46,6 +46,7 @@
 import org.robolectric.Robolectric;
 import org.robolectric.annotation.Config;
 
+import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
@@ -97,6 +98,7 @@
     @Mock private TestTabModel mTabModel;
     @Mock private WindowAndroid mWindowAndroid;
     @Mock private MultiWindowUtils mMultiWindowUtils;
+    @Mock private ObservableSupplier<Integer> mTabStripHeightSupplier;
 
     private Activity mActivity;
     private TabDragSource mTabDragSource;
@@ -128,6 +130,8 @@
         MultiWindowUtils.setInstanceForTesting(mMultiWindowUtils);
         MultiWindowTestUtils.enableMultiInstance();
 
+        when(mTabStripHeightSupplier.get()).thenReturn(mTabStripHeight);
+
         mTabDragSource =
                 new TabDragSource(
                         mActivity,
@@ -137,7 +141,8 @@
                         mMultiInstanceManager,
                         mDragDropDelegate,
                         mBrowserControlsStateProvider,
-                        mWindowAndroid);
+                        mWindowAndroid,
+                        mTabStripHeightSupplier);
         when(mTabModelSelector.getCurrentModel()).thenReturn(mTabModel);
         mTabDragSource.setTabModelSelector(mTabModelSelector);
     }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinatorTest.java
index d0c1038..a546198 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinatorTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinatorTest.java
@@ -43,7 +43,9 @@
 
 import org.chromium.base.ActivityState;
 import org.chromium.base.ApplicationStatus;
+import org.chromium.base.Callback;
 import org.chromium.base.jank_tracker.PlaceholderJankTracker;
+import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.Supplier;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.JniMocker;
@@ -67,7 +69,6 @@
 import org.chromium.chrome.browser.signin.services.SigninManager;
 import org.chromium.chrome.browser.tabmodel.EmptyTabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelObserver;
-import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
 import org.chromium.chrome.browser.xsurface.HybridListRenderer;
 import org.chromium.chrome.browser.xsurface.ProcessScope;
@@ -109,7 +110,6 @@
     ChromeFeatureList.WEB_FEED,
     ChromeFeatureList.WEB_FEED_SORT,
     ChromeFeatureList.WEB_FEED_ONBOARDING,
-    ChromeFeatureList.INTEREST_FEED_V2_AUTOPLAY,
     ChromeFeatureList.FEED_USER_INTERACTION_RELIABILITY_REPORT,
     // TODO(crbug.com/1353777): Disabling the feature explicitly, because native is not
     // available to provide a default value. This should be enabled if the feature is enabled by
@@ -215,12 +215,13 @@
     @Mock private FeedLaunchReliabilityLogger mLaunchReliabilityLogger;
     @Mock private PrivacyPreferencesManagerImpl mPrivacyPreferencesManager;
     @Mock private Tracker mTracker;
-    @Mock private TabModelSelector mTabModelSelector;
     @Mock private ScrollableContainerDelegate mScrollableContainerDelegate;
+    @Mock ObservableSupplier<Integer> mTabStripHeightSupplier;
 
     @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
 
     private FeedSurfaceMediator mMediatorSpy;
+    private int mTabStripHeight;
 
     @Before
     public void setUp() {
@@ -277,11 +278,12 @@
                 .thenReturn(mRecyclerView);
         when(mSurfaceScope.getLaunchReliabilityLogger()).thenReturn(mLaunchReliabilityLogger);
         TrackerFactory.setTrackerForTests(mTracker);
-        when(mTabModelSelector.getModel(eq(false))).thenReturn(mTabModel);
-        when(mTabModelSelector.getModel(eq(true))).thenReturn(mTabModelIncognito);
 
         ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.CREATED);
 
+        mTabStripHeight = mActivity.getResources().getDimensionPixelSize(R.dimen.tab_strip_height);
+        when(mTabStripHeightSupplier.get()).thenReturn(mTabStripHeight);
+
         mCoordinator = createCoordinator();
 
         mRecyclerView.setLayoutManager(mLayoutManager);
@@ -498,6 +500,18 @@
         assertFalse(mCoordinator.shouldDisplaySupervisedFeed());
     }
 
+    @Test
+    public void testTabStripHeightChangeCallback() {
+        ArgumentCaptor<Callback<Integer>> captor = ArgumentCaptor.forClass(Callback.class);
+        verify(mTabStripHeightSupplier).addObserver(captor.capture());
+        Callback<Integer> tabStripHeightChangeCallback = captor.getValue();
+        tabStripHeightChangeCallback.onResult(mTabStripHeight);
+        assertEquals(
+                "Top padding of root view should be updated when tab strip height changes.",
+                mTabStripHeight,
+                mCoordinator.getRootViewForTesting().getPaddingTop());
+    }
+
     private AccountInfo createFakeAccount(boolean isChild) {
         AccountCapabilities capabilities =
                 new AccountCapabilities(
@@ -562,6 +576,6 @@
                 /* viewportView= */ null,
                 mFeedActionDelegate,
                 /* helpAndFeedbackLauncher= */ null,
-                mTabModelSelector);
+                mTabStripHeightSupplier);
     }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/native_page/NativePageFactoryTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/native_page/NativePageFactoryTest.java
index 7305778..de7ee7c17 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/native_page/NativePageFactoryTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/native_page/NativePageFactoryTest.java
@@ -92,7 +92,7 @@
         private MockNativePageBuilder() {
             super(
                     null, null, null, null, null, null, null, null, null, null, null, null, null,
-                    null);
+                    null, null);
         }
 
         @Override
@@ -121,7 +121,7 @@
         mNativePageFactory =
                 new NativePageFactory(
                         null, null, null, null, null, null, null, null, null, null, null, null,
-                        null);
+                        null, null);
         mNativePageFactory.setNativePageBuilderForTesting(new MockNativePageBuilder());
     }
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkInstallBroadcastReceiverTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkInstallBroadcastReceiverTest.java
index f7c2cc7..4b243c7f7 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkInstallBroadcastReceiverTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkInstallBroadcastReceiverTest.java
@@ -4,9 +4,7 @@
 
 package org.chromium.chrome.browser.webapps;
 
-import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.notNull;
-import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.robolectric.Shadows.shadowOf;
@@ -56,7 +54,6 @@
     private Context mContext;
     private ShadowNotificationManager mShadowNotificationManager;
 
-    @Mock public WebApkInstallCoordinatorBridge mBridge;
     @Mock private Context mContextMock;
 
     private WebApkInstallBroadcastReceiver mReceiver;
@@ -68,7 +65,7 @@
         mContext = spy(RuntimeEnvironment.application);
         ContextUtils.initApplicationContextForTests(mContext);
 
-        mReceiver = new WebApkInstallBroadcastReceiver(mBridge);
+        mReceiver = new WebApkInstallBroadcastReceiver();
 
         mShadowNotificationManager =
                 shadowOf(
@@ -80,14 +77,13 @@
                 URL,
                 mIcon,
                 /* isIconMaskable= */ false,
-                WebApkInstallResult.FAILURE,
-                mSerializedProto);
+                WebApkInstallResult.FAILURE);
     }
 
     private Intent createActionIntent(String action) {
         PendingIntentProvider provider =
                 WebApkInstallBroadcastReceiver.createPendingIntent(
-                        mContext, MANIFEST_URL, URL, action, mSerializedProto);
+                        mContext, MANIFEST_URL, URL, action);
         ShadowPendingIntent shadow = shadowOf(provider.getPendingIntent());
         Intent intent = shadow.getSavedIntents()[0];
         Assert.assertNotNull(intent);
@@ -103,27 +99,4 @@
         Assert.assertEquals(0, mShadowNotificationManager.getAllNotifications().size());
         verify(mContext).startActivity(notNull());
     }
-
-    @Test
-    public void testRetryInstallAction() {
-        Intent intent = createActionIntent(WebApkInstallBroadcastReceiver.ACTION_RETRY_INSTALL);
-
-        mReceiver.onReceive(mContext, intent);
-
-        Assert.assertEquals(0, mShadowNotificationManager.getAllNotifications().size());
-        verify(mBridge).retry(any(), any(), any());
-    }
-
-    @Test(expected = AssertionError.class)
-    public void testRetryInstallActionWithoutProto() {
-        Intent intent = createActionIntent(WebApkInstallBroadcastReceiver.ACTION_RETRY_INSTALL);
-        intent.putExtra(WebApkInstallBroadcastReceiver.RETRY_PROTO, (byte[]) null);
-
-        mReceiver.onReceive(mContext, intent);
-
-        Assert.assertEquals(0, mShadowNotificationManager.getAllNotifications().size());
-        // Verify it opens the startUrl when no valid proto to retry.
-        verify(mContext).startActivity(notNull());
-        verify(mBridge, never()).retry(any(), any(), any());
-    }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkInstallNotificationTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkInstallNotificationTest.java
index bd527394..c94852cc 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkInstallNotificationTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkInstallNotificationTest.java
@@ -74,7 +74,6 @@
                             MANIFEST_URL, SHORT_NAME, URL, mIcon, /* isIconMaskable= */ false);
                 });
 
-        String notificationId = WebApkInstallService.getInstallNotificationTag(MANIFEST_URL);
         Notification notification = mShadowNotificationManager.getAllNotifications().get(0);
 
         Assert.assertNotNull(notification);
@@ -134,8 +133,7 @@
                 URL,
                 mIcon,
                 /* isIconMaskable= */ false,
-                WebApkInstallResult.FAILURE,
-                null);
+                WebApkInstallResult.FAILURE);
 
         Notification notification = mShadowNotificationManager.getAllNotifications().get(0);
 
@@ -167,54 +165,4 @@
                 mContext.getString(R.string.webapk_install_failed_action_open), actions[0].title);
         Assert.assertNotNull(actions[0].actionIntent);
     }
-
-    @Test
-    @EnableFeatures({
-        ChromeFeatureList.WEB_APK_INSTALL_FAILURE_NOTIFICATION,
-        ChromeFeatureList.WEB_APK_INSTALL_RETRY
-    })
-    public void testFailureNotificationWithRetryAction() {
-        byte[] serializedProto = new byte[] {1, 2};
-        WebApkInstallService.showInstallFailedNotification(
-                MANIFEST_URL,
-                SHORT_NAME,
-                URL,
-                mIcon,
-                /* isIconMaskable= */ false,
-                WebApkInstallResult.FAILURE,
-                serializedProto);
-
-        Notification notification = mShadowNotificationManager.getAllNotifications().get(0);
-
-        Assert.assertNotNull(notification);
-        Assert.assertEquals(
-                mContext.getString(R.string.notification_webapk_install_failed, SHORT_NAME),
-                notification.extras.getString(Notification.EXTRA_TITLE));
-        Assert.assertEquals(
-                ChromeChannelDefinitions.ChannelId.WEBAPPS, notification.getChannelId());
-        Assert.assertEquals(
-                mContext.getString(
-                        R.string.notification_webapk_install_failed_contents_general, SHORT_NAME),
-                notification.extras.getString(Notification.EXTRA_TEXT));
-
-        Bitmap largeIcon =
-                ((BitmapDrawable) notification.getLargeIcon().loadDrawable(mContext)).getBitmap();
-        Assert.assertTrue(mIcon.sameAs(largeIcon));
-        Bitmap expectedSmallIcon =
-                BitmapFactory.decodeResource(mContext.getResources(), R.drawable.ic_chrome);
-        Bitmap smallIcon =
-                ((BitmapDrawable) notification.getSmallIcon().loadDrawable(mContext)).getBitmap();
-        Assert.assertTrue(expectedSmallIcon.sameAs(smallIcon));
-
-        Assert.assertNotNull(notification.contentIntent);
-
-        Action[] actions = notification.actions;
-        Assert.assertEquals(2, actions.length);
-        Assert.assertEquals(
-                mContext.getString(R.string.webapk_install_failed_action_retry), actions[0].title);
-        Assert.assertNotNull(actions[0].actionIntent);
-        Assert.assertEquals(
-                mContext.getString(R.string.webapk_install_failed_action_open), actions[1].title);
-        Assert.assertNotNull(actions[1].actionIntent);
-    }
 }
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index dfe6797..ea574b1 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2978,8 +2978,6 @@
       "android/webapk/webapk_database.h",
       "android/webapk/webapk_database_factory.cc",
       "android/webapk/webapk_database_factory.h",
-      "android/webapk/webapk_install_coordinator_bridge.cc",
-      "android/webapk/webapk_install_coordinator_bridge.h",
       "android/webapk/webapk_install_service.cc",
       "android/webapk/webapk_install_service.h",
       "android/webapk/webapk_install_service_factory.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 6d1937f..002379c8 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3043,14 +3043,6 @@
     {"15", &kUnthrottledNestedTimeout_NestingLevel, 1, nullptr},
 };
 
-constexpr FeatureEntry::FeatureParam kLensFormatOptimizationWebp[] = {
-    {"use-webp-for-image-search", "true"},
-    {"use-jpeg-for-image-search", "false"}};
-constexpr FeatureEntry::FeatureVariation kLensImageFormatVariations[] = {
-    {"use Webp", kLensFormatOptimizationWebp,
-     std::size(kLensFormatOptimizationWebp), nullptr},
-};
-
 #if BUILDFLAG(ENABLE_LENS_DESKTOP_GOOGLE_BRANDED_FEATURES)
 constexpr FeatureEntry::FeatureParam kCscStagingEnvVariation[] = {
     {"companion-homepage-url",
@@ -5137,10 +5129,6 @@
          kFeatureNotificationGuideSkipCheckForLowEngagedUsersDescription,
      kOsAll,
      FEATURE_VALUE_TYPE(feature_guide::features::kSkipCheckForLowEngagedUsers)},
-    {"offline-pages-live-page-sharing",
-     flag_descriptions::kOfflinePagesLivePageSharingName,
-     flag_descriptions::kOfflinePagesLivePageSharingDescription, kOsAndroid,
-     FEATURE_VALUE_TYPE(offline_pages::kOfflinePagesLivePageSharingFeature)},
     {"query-tiles", flag_descriptions::kQueryTilesName,
      flag_descriptions::kQueryTilesDescription, kOsAndroid,
      FEATURE_WITH_PARAMS_VALUE_TYPE(query_tiles::features::kQueryTiles,
@@ -7182,6 +7170,10 @@
      FEATURE_WITH_PARAMS_VALUE_TYPE(chrome::android::kCCTPageInsightsHub,
                                     kCCTPageInsightsHubVariations,
                                     "CCTPageInsightsHubVariations")},
+    {"cct-page-insights-hub-better-scroll",
+     flag_descriptions::kCCTPageInsightsHubBetterScrollName,
+     flag_descriptions::kCCTPageInsightsHubBetterScrollDescription, kOsAndroid,
+     FEATURE_VALUE_TYPE(chrome::android::kCCTPageInsightsHubBetterScroll)},
     {"cct-resizable-for-third-parties",
      flag_descriptions::kCCTResizableForThirdPartiesName,
      flag_descriptions::kCCTResizableForThirdPartiesDescription, kOsAndroid,
@@ -8939,14 +8931,6 @@
      FEATURE_VALUE_TYPE(lens::features::kLensRegionSearchStaticPage)},
 #endif  // BUILDFLAG(ENABLE_LENS_DESKTOP_GOOGLE_BRANDED_FEATURES)
 
-    {"enable-lens-image-format-optimizations",
-     flag_descriptions::kLensImageFormatOptimizationsName,
-     flag_descriptions::kLensImageFormatOptimizationsDescription, kOsDesktop,
-     FEATURE_WITH_PARAMS_VALUE_TYPE(
-         lens::features::kLensImageFormatOptimizations,
-         kLensImageFormatVariations,
-         "LensImageFormatOptimizations")},
-
     {"enable-lens-image-translate", flag_descriptions::kLensImageTranslateName,
      flag_descriptions::kLensImageTranslateDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(lens::features::kEnableImageTranslate)},
diff --git a/chrome/browser/android/webapk/webapk_install_coordinator_bridge.cc b/chrome/browser/android/webapk/webapk_install_coordinator_bridge.cc
deleted file mode 100644
index 47b3ca8f..0000000
--- a/chrome/browser/android/webapk/webapk_install_coordinator_bridge.cc
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/android/webapk/webapk_install_coordinator_bridge.h"
-
-#include <utility>
-
-#include "base/android/jni_android.h"
-#include "base/android/jni_array.h"
-#include "base/android/jni_string.h"
-#include "base/functional/bind.h"
-#include "base/task/bind_post_task.h"
-#include "base/task/sequenced_task_runner.h"
-#include "base/task/task_traits.h"
-#include "base/task/thread_pool.h"
-#include "chrome/android/chrome_jni_headers/WebApkInstallCoordinatorBridge_jni.h"
-#include "chrome/browser/android/webapk/webapk_install_service.h"
-#include "chrome/browser/android/webapk/webapk_metrics.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
-#include "ui/gfx/android/java_bitmap.h"
-
-using base::android::ConvertJavaStringToUTF8;
-using base::android::JavaParamRef;
-using base::android::ScopedJavaLocalRef;
-
-namespace {
-
-std::string JavaByteArrayToString(
-    JNIEnv* env,
-    const base::android::JavaRef<jbyteArray>& byte_array) {
-  std::string result;
-  base::android::JavaByteArrayToString(env, byte_array, &result);
-  return result;
-}
-
-}  // namespace
-
-namespace webapps {
-
-WebApkInstallCoordinatorBridge::WebApkInstallCoordinatorBridge(
-    JNIEnv* env,
-    const base::android::JavaRef<jobject>& obj)
-    : java_ref_(env, obj),
-      sequenced_task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
-          {base::TaskPriority::BEST_EFFORT})) {}
-
-WebApkInstallCoordinatorBridge::~WebApkInstallCoordinatorBridge() = default;
-
-// static
-jlong JNI_WebApkInstallCoordinatorBridge_Init(
-    JNIEnv* env,
-    const base::android::JavaParamRef<jobject>& obj) {
-  return reinterpret_cast<intptr_t>(
-      new WebApkInstallCoordinatorBridge(env, obj));
-}
-
-void WebApkInstallCoordinatorBridge::Destroy(JNIEnv* env) {
-  delete this;
-}
-
-void WebApkInstallCoordinatorBridge::Install(
-    JNIEnv* env,
-    const base::android::JavaParamRef<jobject>& obj,
-    const base::android::JavaParamRef<jbyteArray>& java_serialized_proto,
-    const base::android::JavaParamRef<jobject>& java_primary_icon,
-    const jboolean is_primary_icon_maskable) {
-  // Use java byte array instead of string as the encoded icons cause problems
-  // when converting as strings between Java and C++.
-  auto serialized_proto = std::make_unique<std::string>(
-      JavaByteArrayToString(env, java_serialized_proto));
-  const SkBitmap primary_icon =
-      gfx::CreateSkBitmapFromJavaBitmap(gfx::JavaBitmap(java_primary_icon));
-
-  // The WebAPK installation with WebApkInstallService needs to run on the UI
-  // thread as the Profile needs to be accessed. The callback has a weak_ptr
-  // from the weak_ptr_factory which lives on the binder thread, so it also
-  // needs to be called on this thread. Using PostTaskAndReply{WithResult}
-  // instead would require the InstallOnUiThread-task to return a result instead
-  // of calling the callback itself.
-  content::GetUIThreadTaskRunner({})->PostTask(
-      FROM_HERE,
-      BindOnce(&WebApkInstallCoordinatorBridge::InstallOnUiThread,
-               base::Unretained(this), std::move(serialized_proto),
-               primary_icon, is_primary_icon_maskable,
-               base::BindPostTask(
-                   sequenced_task_runner_,
-                   base::BindOnce(
-                       &WebApkInstallCoordinatorBridge::OnFinishedApkInstall,
-                       weak_ptr_factory_.GetWeakPtr()))));
-}
-
-void WebApkInstallCoordinatorBridge::InstallOnUiThread(
-    std::unique_ptr<std::string> serialized_proto,
-    const SkBitmap& primary_icon,
-    const bool is_primary_icon_maskable,
-    WebApkInstallService::ServiceInstallFinishCallback finish_callback) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  WebApkInstallService::Get(ProfileManager::GetLastUsedProfile())
-      ->InstallForServiceAsync(std::move(serialized_proto), primary_icon,
-                               is_primary_icon_maskable,
-                               std::move(finish_callback));
-}
-
-void WebApkInstallCoordinatorBridge::OnFinishedApkInstall(
-    WebApkInstallResult result) {
-  JNIEnv* env = base::android::AttachCurrentThread();
-  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
-  Java_WebApkInstallCoordinatorBridge_onFinishedInstall(env, obj, (int)result);
-}
-
-void WebApkInstallCoordinatorBridge::Retry(
-    JNIEnv* env,
-    jstring java_webapp_id,
-    const base::android::JavaParamRef<jbyteArray>& java_serialized_proto,
-    const base::android::JavaParamRef<jobject>& java_primary_icon) {
-  GURL install_id = GURL(ConvertJavaStringToUTF8(env, java_webapp_id));
-
-  auto serialized_proto = std::make_unique<std::string>(
-      JavaByteArrayToString(env, java_serialized_proto));
-  const SkBitmap primary_icon =
-      gfx::CreateSkBitmapFromJavaBitmap(gfx::JavaBitmap(java_primary_icon));
-
-  content::GetUIThreadTaskRunner({})->PostTask(
-      FROM_HERE,
-      BindOnce(
-          &WebApkInstallCoordinatorBridge::RetryInstallOnUiThread,
-          base::Unretained(this), std::move(serialized_proto), primary_icon,
-          base::BindPostTask(
-              sequenced_task_runner_,
-              base::BindOnce(&WebApkInstallCoordinatorBridge::OnRetryFinished,
-                             weak_ptr_factory_.GetWeakPtr()))));
-}
-
-void WebApkInstallCoordinatorBridge::OnRetryFinished(
-    WebApkInstallResult result) {
-  webapk::TrackInstallRetryResult(result);
-}
-
-void WebApkInstallCoordinatorBridge::RetryInstallOnUiThread(
-    std::unique_ptr<std::string> serialized_proto,
-    const SkBitmap& primary_icon,
-    WebApkInstallService::ServiceInstallFinishCallback finish_callback) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  WebApkInstallService::Get(ProfileManager::GetLastUsedProfile())
-      ->RetryInstallAsync(std::move(serialized_proto), primary_icon,
-                          false /*is_primary_icon_maskable*/,
-                          std::move(finish_callback));
-}
-
-}  // namespace webapps
diff --git a/chrome/browser/android/webapk/webapk_install_coordinator_bridge.h b/chrome/browser/android/webapk/webapk_install_coordinator_bridge.h
deleted file mode 100644
index a796868..0000000
--- a/chrome/browser/android/webapk/webapk_install_coordinator_bridge.h
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_ANDROID_WEBAPK_WEBAPK_INSTALL_COORDINATOR_BRIDGE_H_
-#define CHROME_BROWSER_ANDROID_WEBAPK_WEBAPK_INSTALL_COORDINATOR_BRIDGE_H_
-
-#include <memory>
-#include <string>
-#include "base/android/jni_android.h"
-#include "base/android/jni_weak_ref.h"
-#include "base/android/scoped_java_ref.h"
-#include "base/functional/callback.h"
-#include "base/memory/weak_ptr.h"
-#include "base/sequence_checker.h"
-#include "base/task/sequenced_task_runner.h"
-#include "base/task/task_traits.h"
-#include "base/task/thread_pool.h"
-#include "chrome/browser/android/webapk/webapk_install_service.h"
-#include "components/webapps/browser/android/shortcut_info.h"
-
-enum class WebApkInstallResult;
-class SkBitmap;
-
-namespace webapps {
-
-enum class WebappInstallSource;
-
-// This class is owned by the Java WebApkInstallCoordinatorBridge object.
-// The Java side is responsible for cleaning up this object.
-class WebApkInstallCoordinatorBridge {
- public:
-  WebApkInstallCoordinatorBridge(JNIEnv* env,
-                                 const base::android::JavaRef<jobject>& obj);
-  ~WebApkInstallCoordinatorBridge();
-
-  WebApkInstallCoordinatorBridge(const WebApkInstallCoordinatorBridge&) =
-      delete;
-  WebApkInstallCoordinatorBridge& operator=(
-      const WebApkInstallCoordinatorBridge&) = delete;
-
-  void Install(JNIEnv* env,
-               const base::android::JavaParamRef<jobject>& obj,
-               const base::android::JavaParamRef<jbyteArray>& java_web_apk,
-               const base::android::JavaParamRef<jobject>& java_primary_icon,
-               const jboolean is_primary_icon_maskable);
-
-  void InstallOnUiThread(
-      std::unique_ptr<std::string> serialized_proto,
-      const SkBitmap& primary_icon,
-      const bool is_primary_icon_maskable,
-      WebApkInstallService::ServiceInstallFinishCallback finish_callback);
-
-  void OnFinishedApkInstall(const WebApkInstallResult result);
-
-  void Retry(
-      JNIEnv* env,
-      jstring start_url,
-      const base::android::JavaParamRef<jbyteArray>& java_serialized_proto,
-      const base::android::JavaParamRef<jobject>& java_primary_icon);
-
-  void OnRetryFinished(const WebApkInstallResult result);
-
-  void Destroy(JNIEnv* env);
-
- private:
-  void RetryInstallOnUiThread(
-      std::unique_ptr<std::string> serialized_proto,
-      const SkBitmap& primary_icon,
-      WebApkInstallService::ServiceInstallFinishCallback finish_callback);
-
-  JavaObjectWeakGlobalRef java_ref_;
-
-  const scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_;
-
-  // Used to get |weak_ptr_|.
-  base::WeakPtrFactory<WebApkInstallCoordinatorBridge> weak_ptr_factory_{this};
-};
-
-}  // namespace webapps
-
-#endif  // CHROME_BROWSER_ANDROID_WEBAPK_WEBAPK_INSTALL_COORDINATOR_BRIDGE_H_
diff --git a/chrome/browser/android/webapk/webapk_install_service.cc b/chrome/browser/android/webapk/webapk_install_service.cc
index 7626d75..ede4e12b 100644
--- a/chrome/browser/android/webapk/webapk_install_service.cc
+++ b/chrome/browser/android/webapk/webapk_install_service.cc
@@ -70,45 +70,6 @@
                      shortcut_info, primary_icon));
 }
 
-void WebApkInstallService::InstallForServiceAsync(
-    std::unique_ptr<std::string> serialized_proto,
-    const SkBitmap& primary_icon,
-    bool is_primary_icon_maskable,
-    ServiceInstallFinishCallback finish_callback) {
-  auto proto = std::make_unique<webapk::WebApk>();
-  if (!proto->ParseFromString(*serialized_proto.get())) {
-    std::move(finish_callback).Run(webapps::WebApkInstallResult::FAILURE);
-    return;
-  }
-
-  GURL manifest_url(proto->manifest_url());
-  GURL manifest_id(proto->manifest().id());
-  if (IsInstallInProgress(manifest_id)) {
-    std::move(finish_callback)
-        .Run(webapps::WebApkInstallResult::INSTALL_ALREADY_IN_PROGRESS);
-    return;
-  }
-  install_ids_.insert(manifest_id);
-  std::u16string short_name = base::UTF8ToUTF16(proto->manifest().short_name());
-  GURL manifest_start_url = GURL(proto->manifest().start_url());
-
-  webapps::InstallableMetrics::TrackInstallEvent(
-      webapps::WebappInstallSource::CHROME_SERVICE);
-
-  ShowInstallInProgressNotification(manifest_id, short_name, manifest_start_url,
-                                    primary_icon, is_primary_icon_maskable);
-
-  WebApkInstaller::InstallWithProtoAsync(
-      browser_context_, std::move(serialized_proto), short_name,
-      webapps::ShortcutInfo::SOURCE_CHROME_SERVICE, primary_icon, manifest_url,
-      base::BindOnce(&WebApkInstallService::OnFinishedInstallWithProto,
-                     weak_ptr_factory_.GetWeakPtr(), manifest_id,
-                     manifest_start_url, short_name, primary_icon,
-                     is_primary_icon_maskable,
-                     webapps::ShortcutInfo::SOURCE_CHROME_SERVICE,
-                     std::move(finish_callback)));
-}
-
 void WebApkInstallService::RetryInstallAsync(
     std::unique_ptr<std::string> serialized_proto,
     const SkBitmap& primary_icon,
@@ -157,15 +118,13 @@
     const webapps::ShortcutInfo& shortcut_info,
     const SkBitmap& primary_icon,
     webapps::WebApkInstallResult result,
-    std::unique_ptr<std::string> serialized_proto,
     bool relax_updates,
     const std::string& webapk_package_name) {
   install_ids_.erase(shortcut_info.manifest_id);
   HandleFinishInstallNotifications(
       shortcut_info.manifest_id, shortcut_info.url, shortcut_info.short_name,
       primary_icon, shortcut_info.is_primary_icon_maskable,
-      shortcut_info.source, result, std::move(serialized_proto),
-      webapk_package_name);
+      shortcut_info.source, result, webapk_package_name);
 
   if (base::FeatureList::IsEnabled(
           webapps::features::kWebApkInstallFailureNotification)) {
@@ -197,14 +156,13 @@
     webapps::ShortcutInfo::Source source,
     ServiceInstallFinishCallback finish_callback,
     webapps::WebApkInstallResult result,
-    std::unique_ptr<std::string> serialized_proto,
     bool relax_updates,
     const std::string& webapk_package_name) {
   install_ids_.erase(manifest_id);
 
-  HandleFinishInstallNotifications(
-      manifest_id, url, short_name, primary_icon, is_primary_icon_maskable,
-      source, result, std::move(serialized_proto), webapk_package_name);
+  HandleFinishInstallNotifications(manifest_id, url, short_name, primary_icon,
+                                   is_primary_icon_maskable, source, result,
+                                   webapk_package_name);
 
   std::move(finish_callback).Run(result);
 }
@@ -217,22 +175,10 @@
     bool is_primary_icon_maskable,
     webapps::ShortcutInfo::Source source,
     webapps::WebApkInstallResult result,
-    std::unique_ptr<std::string> serialized_proto,
     const std::string& webapk_package_name) {
   if (result == webapps::WebApkInstallResult::SUCCESS) {
     ShowInstalledNotification(notification_id, short_name, url, primary_icon,
                               is_primary_icon_maskable, webapk_package_name);
-  } else if (base::FeatureList::IsEnabled(
-                 webapps::features::kWebApkInstallFailureNotification) &&
-             result != webapps::WebApkInstallResult::PROBABLE_FAILURE) {
-    if (source == webapps::ShortcutInfo::SOURCE_INSTALL_RETRY ||
-        !serialized_proto) {
-      // Set to empty string to indicate retry is not available.
-      serialized_proto = std::make_unique<std::string>();
-    }
-    ShowInstallFailedNotification(notification_id, short_name, url,
-                                  primary_icon, is_primary_icon_maskable,
-                                  result, std::move(serialized_proto));
   } else {
     JNIEnv* env = base::android::AttachCurrentThread();
     base::android::ScopedJavaLocalRef<jstring> java_notification_id =
@@ -295,8 +241,7 @@
     const GURL& url,
     const SkBitmap& primary_icon,
     bool is_primary_icon_maskable,
-    webapps::WebApkInstallResult result,
-    std::unique_ptr<std::string> serialized_proto) {
+    webapps::WebApkInstallResult result) {
   JNIEnv* env = base::android::AttachCurrentThread();
   base::android::ScopedJavaLocalRef<jstring> java_notification_id =
       base::android::ConvertUTF8ToJavaString(env, notification_id.spec());
@@ -306,11 +251,8 @@
       base::android::ConvertUTF8ToJavaString(env, url.spec());
   base::android::ScopedJavaLocalRef<jobject> java_primary_icon =
       gfx::ConvertToJavaBitmap(primary_icon);
-  base::android::ScopedJavaLocalRef<jbyteArray> java_serialized_proto =
-      base::android::ToJavaByteArray(env, *serialized_proto);
 
   Java_WebApkInstallService_showInstallFailedNotification(
       env, java_notification_id, java_short_name, java_url, java_primary_icon,
-      is_primary_icon_maskable, static_cast<int>(result),
-      java_serialized_proto);
+      is_primary_icon_maskable, static_cast<int>(result));
 }
diff --git a/chrome/browser/android/webapk/webapk_install_service.h b/chrome/browser/android/webapk/webapk_install_service.h
index 01847646..88da3db6 100644
--- a/chrome/browser/android/webapk/webapk_install_service.h
+++ b/chrome/browser/android/webapk/webapk_install_service.h
@@ -42,12 +42,10 @@
   // Called when the creation/updating of a WebAPK is finished or failed.
   // Parameters:
   // - the result of the installation.
-  // - serialized proto for the installation, if exist.
   // - true if Chrome received a "request updates less frequently" directive.
   //   from the WebAPK server.
   // - the package name of the WebAPK.
   using FinishCallback = base::OnceCallback<void(webapps::WebApkInstallResult,
-                                                 std::unique_ptr<std::string>,
                                                  bool,
                                                  const std::string&)>;
 
@@ -83,18 +81,6 @@
                          bool is_primary_icon_maskable,
                          ServiceInstallFinishCallback finish_callback);
 
-  // This function is used if the install is scheduled in the
-  // WebApkInstallCoordinatorService service. Installs WebAPKs based on a
-  // serialized_web_apk it receives from the client. It
-  // talks to the Chrome WebAPK server to generate a WebAPK on the server and to
-  // Google Play to install the downloaded WebAPK. It calls the
-  // |finish_callback| with the result of the installation to propagate the
-  // result to the connecting client.
-  void InstallForServiceAsync(std::unique_ptr<std::string> serialized_web_apk,
-                              const SkBitmap& primary_icon,
-                              bool is_primary_icon_maskable,
-                              ServiceInstallFinishCallback finish_callback);
-
   // Talks to the Chrome WebAPK server to update a WebAPK on the server and to
   // the Google Play server to install the downloaded WebAPK.
   // |update_request_path| is the path of the file with the update request.
@@ -108,7 +94,6 @@
                          const webapps::ShortcutInfo& shortcut_info,
                          const SkBitmap& primary_icon,
                          webapps::WebApkInstallResult result,
-                         std::unique_ptr<std::string> serialized_webapk,
                          bool relax_updates,
                          const std::string& webapk_package_name);
 
@@ -124,7 +109,6 @@
       webapps::ShortcutInfo::Source source,
       ServiceInstallFinishCallback done_callback,
       webapps::WebApkInstallResult result,
-      std::unique_ptr<std::string> serialized_webapk,
       bool relax_updates,
       const std::string& webapk_package_name);
 
@@ -138,7 +122,6 @@
       bool is_primary_icon_maskable,
       webapps::ShortcutInfo::Source source,
       webapps::WebApkInstallResult result,
-      std::unique_ptr<std::string> serialized_webapk,
       const std::string& webapk_package_name);
 
   // Shows a notification that an install is in progress.
@@ -164,8 +147,7 @@
       const GURL& url,
       const SkBitmap& primary_icon,
       bool is_primary_icon_maskable,
-      webapps::WebApkInstallResult result,
-      std::unique_ptr<std::string> serialized_webapk);
+      webapps::WebApkInstallResult result);
 
   raw_ptr<content::BrowserContext> browser_context_;
 
diff --git a/chrome/browser/android/webapk/webapk_installer.cc b/chrome/browser/android/webapk/webapk_installer.cc
index daf15c7..ccb3bb77 100644
--- a/chrome/browser/android/webapk/webapk_installer.cc
+++ b/chrome/browser/android/webapk/webapk_installer.cc
@@ -263,9 +263,7 @@
 void WebApkInstaller::OnResult(webapps::WebApkInstallResult result) {
   weak_ptr_factory_.InvalidateWeakPtrs();
 
-  std::move(finish_callback_)
-      .Run(result, std::move(serialized_webapk_), relax_updates_,
-           webapk_package_);
+  std::move(finish_callback_).Run(result, relax_updates_, webapk_package_);
 
   if (task_type_ == WebApkInstaller::INSTALL) {
     if (result == webapps::WebApkInstallResult::SUCCESS) {
diff --git a/chrome/browser/android/webapk/webapk_installer_browsertest.cc b/chrome/browser/android/webapk/webapk_installer_browsertest.cc
index 54e87be..64a723c39 100644
--- a/chrome/browser/android/webapk/webapk_installer_browsertest.cc
+++ b/chrome/browser/android/webapk/webapk_installer_browsertest.cc
@@ -156,7 +156,6 @@
 
  private:
   void OnCompleted(webapps::WebApkInstallResult result,
-                   std::unique_ptr<std::string> serialized_webapk,
                    bool relax_updates,
                    const std::string& webapk_package) {
     result_ = result;
diff --git a/chrome/browser/android/webapk/webapk_update_manager.cc b/chrome/browser/android/webapk/webapk_update_manager.cc
index a9f11d92..8868a0e3 100644
--- a/chrome/browser/android/webapk/webapk_update_manager.cc
+++ b/chrome/browser/android/webapk/webapk_update_manager.cc
@@ -42,7 +42,6 @@
 // Called after the update either succeeds or fails.
 void OnUpdated(const JavaRef<jobject>& java_callback,
                webapps::WebApkInstallResult result,
-               std::unique_ptr<std::string> serialized_proto,
                bool relax_updates,
                const std::string& webapk_package) {
   JNIEnv* env = base::android::AttachCurrentThread();
@@ -256,7 +255,6 @@
         FROM_HERE,
         base::BindOnce(&OnUpdated, callback_ref,
                        webapps::WebApkInstallResult::FAILURE,
-                       nullptr /* serialized_proto */,
                        false /* relax_updates */, "" /* webapk_package */));
     return;
   }
diff --git a/chrome/browser/ash/accessibility/automation_test_utils.cc b/chrome/browser/ash/accessibility/automation_test_utils.cc
index 4e23a21..c943623 100644
--- a/chrome/browser/ash/accessibility/automation_test_utils.cc
+++ b/chrome/browser/ash/accessibility/automation_test_utils.cc
@@ -105,6 +105,13 @@
   return script_result == "true";
 }
 
+void AutomationTestUtils::DoDefault(const std::string& name,
+                                    const std::string& role) {
+  ExecuteScriptInExtensionPage(base::StringPrintf(
+      R"JS(globalThis.automationTestSupport.doDefault(`%s`, `%s`))JS",
+      name.c_str(), role.c_str()));
+}
+
 void AutomationTestUtils::WaitForTextSelectionChangedEvent() {
   std::string script = R"(
     globalThis.automationTestSupport.waitForTextSelectionChangedEvent();
diff --git a/chrome/browser/ash/accessibility/automation_test_utils.h b/chrome/browser/ash/accessibility/automation_test_utils.h
index 8dff5ce..7fb31c2 100644
--- a/chrome/browser/ash/accessibility/automation_test_utils.h
+++ b/chrome/browser/ash/accessibility/automation_test_utils.h
@@ -61,6 +61,9 @@
   // node does not exist.
   bool NodeExistsNoWait(const std::string& name, const std::string& role);
 
+  // Does the default action on the node with `name` and `role`.
+  void DoDefault(const std::string& name, const std::string& role);
+
   // Various event waiters. This is the automation equivalent of
   // AccessibilityNotificationWaiter.
 
diff --git a/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc b/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc
index 0efbc5e..ff5715d 100644
--- a/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc
+++ b/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc
@@ -34,6 +34,7 @@
 #include "base/functional/bind.h"
 #include "base/memory/raw_ptr.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/bind.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "build/build_config.h"
@@ -942,6 +943,38 @@
   sm_.Replay();
 }
 
+IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, OpenSettingsFromPanel) {
+  EnableChromeVox();
+
+  AutomationTestUtils test_utils(extension_misc::kChromeVoxExtensionId);
+  sm_.Call([&test_utils]() { test_utils.SetUpTestSupport(); });
+
+  base::RunLoop waiter;
+  AccessibilityManager::Get()->SetOpenSettingsSubpageObserverForTest(
+      base::BindLambdaForTesting([&waiter]() { waiter.Quit(); }));
+
+  // Find the settings button in the panel.
+  sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_OEM_PERIOD); });
+  sm_.ExpectSpeech("Search the menus");
+  sm_.Call([this]() {
+    SendKeyPress(ui::VKEY_TAB);
+    SendKeyPress(ui::VKEY_TAB);
+  });
+  sm_.ExpectSpeech("ChromeVox Menus collapse");
+  sm_.Call([this]() { SendKeyPress(ui::VKEY_TAB); });
+  sm_.ExpectSpeech("ChromeVox Options");
+
+  // TODO(b/316916793): We cannot click this button with ChromeVox directly, so
+  // using test utils for now.
+  sm_.Call(
+      [&test_utils]() { test_utils.DoDefault("ChromeVox Options", "button"); });
+
+  sm_.Replay();
+
+  // We should have tried to open the settings subpage.
+  waiter.Run();
+}
+
 // Fails on ASAN. See http://crbug.com/776308 . (Note MAYBE_ doesn't work well
 // with parameterized tests).
 #if !defined(ADDRESS_SANITIZER)
diff --git a/chrome/browser/ash/app_restore/full_restore_app_launch_handler_browsertest.cc b/chrome/browser/ash/app_restore/full_restore_app_launch_handler_browsertest.cc
index fa9a2608..00a8d79 100644
--- a/chrome/browser/ash/app_restore/full_restore_app_launch_handler_browsertest.cc
+++ b/chrome/browser/ash/app_restore/full_restore_app_launch_handler_browsertest.cc
@@ -1025,9 +1025,10 @@
   EXPECT_EQ(kCurrentBounds, browser_bounds);
 }
 
+// TODO(crbug/1512721): Re-enable this test when the flakiness issue is fixed.
 // Test Lacros window properties and bounds are restored correctly.
 IN_PROC_BROWSER_TEST_F(FullRestoreAppLaunchHandlerBrowserTest,
-                       RestoreLacrosWindowProperties) {
+                       DISABLED_RestoreLacrosWindowProperties) {
   gfx::Size size(32, 32);
   gfx::Point origin(100, 100);
   gfx::Rect prerestore_bounds(origin, size);
diff --git a/chrome/browser/ash/bluetooth/bluetooth_integration_test.cc b/chrome/browser/ash/bluetooth/bluetooth_integration_test.cc
index 4e984c1..9a4f4a63 100644
--- a/chrome/browser/ash/bluetooth/bluetooth_integration_test.cc
+++ b/chrome/browser/ash/bluetooth/bluetooth_integration_test.cc
@@ -17,7 +17,7 @@
 #include "base/test/test_switches.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/settings_window_manager_chromeos.h"
-#include "chrome/test/base/chromeos/crosier/interactive_ash_test.h"
+#include "chrome/test/base/chromeos/crosier/ash_integration_test.h"
 #include "dbus/object_path.h"
 #include "device/bluetooth/dbus/bluetooth_adapter_client.h"
 #include "device/bluetooth/dbus/bluez_dbus_manager.h"
@@ -71,16 +71,16 @@
 constexpr char kCheckJsElementIsNotChecked[] =
     "(el) => { return !el.checked; }";
 
-class BluetoothIntegrationTest : public InteractiveAshTest {
+class BluetoothIntegrationTest : public AshIntegrationTest {
  public:
   BluetoothIntegrationTest() {
     // Use the legacy bluez bluetooth stack.
     feature_list_.InitAndDisableFeature(floss::features::kFlossEnabled);
   }
 
-  // InteractiveAshTest:
+  // AshIntegrationTest:
   void SetUpOnMainThread() override {
-    InteractiveAshTest::SetUpOnMainThread();
+    AshIntegrationTest::SetUpOnMainThread();
 
     bluez_dbus_manager_ = BluezDBusManager::Get();
     if (!bluez_dbus_manager_) {
@@ -109,7 +109,7 @@
     adapter_client_ = nullptr;
     bluez_dbus_manager_ = nullptr;
 
-    InteractiveAshTest::TearDownOnMainThread();
+    AshIntegrationTest::TearDownOnMainThread();
   }
 
   // Waits for a toggle element to be toggled (which is represented as "checked"
diff --git a/chrome/browser/ash/external_metrics_integration_test.cc b/chrome/browser/ash/external_metrics_integration_test.cc
index fccb722d..e0a4048 100644
--- a/chrome/browser/ash/external_metrics_integration_test.cc
+++ b/chrome/browser/ash/external_metrics_integration_test.cc
@@ -8,7 +8,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "chrome/browser/ash/external_metrics.h"
-#include "chrome/test/base/chromeos/crosier/interactive_ash_test.h"
+#include "chrome/test/base/chromeos/crosier/ash_integration_test.h"
 
 namespace ash {
 namespace {
@@ -23,7 +23,7 @@
 
 const char kTestHistogramName[] = "ExternalMetricsIntegrationTest.Histogram";
 
-class ExternalMetricsIntegrationTest : public InteractiveAshTest {
+class ExternalMetricsIntegrationTest : public AshIntegrationTest {
  public:
   void ReportMetrics(int num_samples, int value, int max) {
     std::vector<std::string> args{kMetricsClientBinaryName};
diff --git a/chrome/browser/ash/featured_integration_test.cc b/chrome/browser/ash/featured_integration_test.cc
index 4676184b..23281bfd 100644
--- a/chrome/browser/ash/featured_integration_test.cc
+++ b/chrome/browser/ash/featured_integration_test.cc
@@ -13,9 +13,9 @@
 #include "base/task/task_traits.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/values.h"
+#include "chrome/test/base/chromeos/crosier/ash_integration_test.h"
 #include "chrome/test/base/chromeos/crosier/chromeos_test_definition.pb.h"
 #include "chrome/test/base/chromeos/crosier/crosier_util.h"
-#include "chrome/test/base/chromeos/crosier/interactive_ash_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
@@ -40,7 +40,7 @@
   const char* expected_default_disabled = "";
 };
 
-class FeaturedIntegrationTest : public InteractiveAshTest,
+class FeaturedIntegrationTest : public AshIntegrationTest,
                                 public ::testing::WithParamInterface<TestCase> {
  public:
   FeaturedIntegrationTest() {
@@ -48,9 +48,9 @@
                                       GetParam().disabled_features);
   }
 
-  // InteractiveAshTest:
+  // AshIntegrationTest:
   void SetUpOnMainThread() override {
-    InteractiveAshTest::SetUpOnMainThread();
+    AshIntegrationTest::SetUpOnMainThread();
 
     chrome_test_base_chromeos_crosier::TestInfo info;
     info.set_description(
diff --git a/chrome/browser/ash/login/demo_mode/demo_session.cc b/chrome/browser/ash/login/demo_mode/demo_session.cc
index fbe934d..c9c08ffe 100644
--- a/chrome/browser/ash/login/demo_mode/demo_session.cc
+++ b/chrome/browser/ash/login/demo_mode/demo_session.cc
@@ -698,6 +698,15 @@
       if (ash::features::IsDemoModeGMSCoreWindowCloserEnabled()) {
         window_closer_ = std::make_unique<DemoModeWindowCloser>();
       }
+
+      // TODO(b/292454543): Remove this after issue is resolved.
+      if (InstallAttributes::IsInitialized()) {
+        LOG(WARNING) << "Demo Mode DeviceMode: "
+                     << InstallAttributes::Get()->GetMode();
+        LOG(WARNING) << "Demo Mode domain: "
+                     << InstallAttributes::Get()->GetDomain();
+      }
+
       break;
     default:
       break;
diff --git a/chrome/browser/ash/login/enrollment/enrollment_embedded_policy_server_browsertest.cc b/chrome/browser/ash/login/enrollment/enrollment_embedded_policy_server_browsertest.cc
index de47382..0dfc52eb 100644
--- a/chrome/browser/ash/login/enrollment/enrollment_embedded_policy_server_browsertest.cc
+++ b/chrome/browser/ash/login/enrollment/enrollment_embedded_policy_server_browsertest.cc
@@ -63,8 +63,10 @@
 #include "content/public/test/test_utils.h"
 #include "net/http/http_status_code.h"
 
-// TODO(https://crbug.com/1512521): Failing on ASan/Lsan builder on Linux.
-#if defined(ADDRESS_SANITIZER) && BUILDFLAG(IS_LINUX)
+// TODO(https://crbug.com/1512521): Failing on ASan/Lsan builder on Linux and
+// ChromeOS.
+#if defined(ADDRESS_SANITIZER) && \
+    (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS))
 #define MAYBE_ASAN(x) DISABLED_##x
 #else
 #define MAYBE_ASAN(x) x
diff --git a/chrome/browser/ash/login/lock/lock_screen_integration_test.cc b/chrome/browser/ash/login/lock/lock_screen_integration_test.cc
index 7653efb..c64654c 100644
--- a/chrome/browser/ash/login/lock/lock_screen_integration_test.cc
+++ b/chrome/browser/ash/login/lock/lock_screen_integration_test.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/test/base/chromeos/crosier/interactive_ash_test.h"
+#include "chrome/test/base/chromeos/crosier/ash_integration_test.h"
 
 #include "ash/constants/ash_pref_names.h"
 #include "ash/shell.h"
@@ -16,7 +16,7 @@
 
 namespace {
 
-using LockScreen = InteractiveAshTest;
+using LockScreen = AshIntegrationTest;
 
 }  // namespace
 
diff --git a/chrome/browser/ash/login/login_integration_test.cc b/chrome/browser/ash/login/login_integration_test.cc
index d9873c4..03e0373 100644
--- a/chrome/browser/ash/login/login_integration_test.cc
+++ b/chrome/browser/ash/login/login_integration_test.cc
@@ -7,10 +7,10 @@
 
 #include "build/branding_buildflags.h"
 #include "chrome/browser/ash/login/test/session_manager_state_waiter.h"
+#include "chrome/test/base/chromeos/crosier/ash_integration_test.h"
 #include "chrome/test/base/chromeos/crosier/chromeos_integration_login_mixin.h"
-#include "chrome/test/base/chromeos/crosier/interactive_ash_test.h"
 
-class LoginIntegrationTest : public InteractiveAshTest {
+class LoginIntegrationTest : public AshIntegrationTest {
  public:
   LoginIntegrationTest() {
     set_exit_when_last_browser_closes(false);
@@ -35,7 +35,7 @@
 
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 // Gaia login is only supported for branded build.
-class GaiaLoginIntegrationTest : public InteractiveAshTest {
+class GaiaLoginIntegrationTest : public AshIntegrationTest {
  public:
   GaiaLoginIntegrationTest() {
     set_exit_when_last_browser_closes(false);
diff --git a/chrome/browser/ash/ml_integration_test.cc b/chrome/browser/ash/ml_integration_test.cc
index 708a1d0d..b8cc08d 100644
--- a/chrome/browser/ash/ml_integration_test.cc
+++ b/chrome/browser/ash/ml_integration_test.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/test/base/chromeos/crosier/interactive_ash_test.h"
+#include "chrome/test/base/chromeos/crosier/ash_integration_test.h"
 
 #include "chrome/test/base/chromeos/crosier/upstart.h"
 #include "chromeos/services/machine_learning/public/cpp/service_connection.h"
@@ -12,7 +12,7 @@
 
 namespace {
 
-using MLIntegrationTest = InteractiveAshTest;
+using MLIntegrationTest = AshIntegrationTest;
 
 }  // namespace
 
diff --git a/chrome/browser/ash/power/ml/smart_dim/smart_dim_integration_test.cc b/chrome/browser/ash/power/ml/smart_dim/smart_dim_integration_test.cc
index 6e52760..9f19c66 100644
--- a/chrome/browser/ash/power/ml/smart_dim/smart_dim_integration_test.cc
+++ b/chrome/browser/ash/power/ml/smart_dim/smart_dim_integration_test.cc
@@ -14,7 +14,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/component_updater/smart_dim_component_installer.h"
 #include "chrome/common/chrome_features.h"
-#include "chrome/test/base/chromeos/crosier/interactive_ash_test.h"
+#include "chrome/test/base/chromeos/crosier/ash_integration_test.h"
 #include "chromeos/ash/components/standalone_browser/standalone_browser_features.h"
 #include "components/component_updater/component_updater_service.h"
 #include "net/dns/mock_host_resolver.h"
@@ -70,7 +70,7 @@
 
 }  // namespace
 
-class SmartDimIntegrationTest : public InteractiveAshTest {
+class SmartDimIntegrationTest : public AshIntegrationTest {
  public:
   SmartDimIntegrationTest() {
     feature_list_.InitAndEnableFeature(features::kSmartDim);
@@ -182,7 +182,7 @@
         ash::standalone_browser::features::kLacrosOnly);
   }
 
-  // InteractiveAshTest:
+  // AshIntegrationTest:
   void SetUpCommandLine(base::CommandLine* command_line) override {
     SmartDimIntegrationTest::SetUpCommandLine(command_line);
     SetUpCommandLineForLacros(command_line);
diff --git a/chrome/browser/ash/scanning/scan_integration_test.cc b/chrome/browser/ash/scanning/scan_integration_test.cc
index b04e6c4..f354c1e 100644
--- a/chrome/browser/ash/scanning/scan_integration_test.cc
+++ b/chrome/browser/ash/scanning/scan_integration_test.cc
@@ -15,8 +15,8 @@
 #include "chrome/browser/ash/scanning/scan_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_paths.h"
+#include "chrome/test/base/chromeos/crosier/ash_integration_test.h"
 #include "chrome/test/base/chromeos/crosier/chromeos_integration_login_mixin.h"
-#include "chrome/test/base/chromeos/crosier/interactive_ash_test.h"
 #include "chrome/test/interaction/interactive_browser_test.h"
 #include "chromeos/ash/components/browser_context_helper/browser_context_types.h"
 #include "chromeos/ash/components/dbus/lorgnette/lorgnette_service.pb.h"
@@ -66,7 +66,7 @@
   return manager;
 }
 
-class ScanIntegrationTest : public InteractiveAshTest {
+class ScanIntegrationTest : public AshIntegrationTest {
  public:
   ScanIntegrationTest() {
     set_exit_when_last_browser_closes(false);
diff --git a/chrome/browser/ash/system_web_apps/apps/terminal_integration_test.cc b/chrome/browser/ash/system_web_apps/apps/terminal_integration_test.cc
index 14bf8a5..9cf83dd 100644
--- a/chrome/browser/ash/system_web_apps/apps/terminal_integration_test.cc
+++ b/chrome/browser/ash/system_web_apps/apps/terminal_integration_test.cc
@@ -8,7 +8,7 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/ash/shelf/chrome_shelf_controller.h"
 #include "chrome/browser/web_applications/web_app_id_constants.h"
-#include "chrome/test/base/chromeos/crosier/interactive_ash_test.h"
+#include "chrome/test/base/chromeos/crosier/ash_integration_test.h"
 #include "ui/aura/env.h"
 #include "ui/base/interaction/polling_state_observer.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
@@ -16,7 +16,7 @@
 
 namespace {
 
-class TerminalIntegrationTest : public InteractiveAshTest {
+class TerminalIntegrationTest : public AshIntegrationTest {
  public:
   // Sends the given text to the element as individual key press commands.
   //
diff --git a/chrome/browser/autofill/mock_autofill_popup_controller.h b/chrome/browser/autofill/mock_autofill_popup_controller.h
index 21ce31b..4ba0da9 100644
--- a/chrome/browser/autofill/mock_autofill_popup_controller.h
+++ b/chrome/browser/autofill/mock_autofill_popup_controller.h
@@ -96,7 +96,8 @@
               RemoveSuggestion,
               (int, AutofillMetrics::SingleEntryRemovalMethod),
               (override));
-  MOCK_METHOD(void, SelectSuggestion, (absl::optional<size_t>), (override));
+  MOCK_METHOD(void, SelectSuggestion, (int), (override));
+  MOCK_METHOD(void, UnselectSuggestion, (), (override));
   MOCK_METHOD(PopupType, GetPopupType, (), (const override));
   MOCK_METHOD(base::WeakPtr<AutofillPopupController>,
               OpenSubPopup,
diff --git a/chrome/browser/cart/cart_handler_unittest.cc b/chrome/browser/cart/cart_handler_unittest.cc
index edc24fa8..0286b92 100644
--- a/chrome/browser/cart/cart_handler_unittest.cc
+++ b/chrome/browser/cart/cart_handler_unittest.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
+#include "components/commerce/core/commerce_constants.h"
 #include "components/commerce/core/commerce_feature_list.h"
 #include "components/commerce/core/commerce_heuristics_data.h"
 #include "components/commerce/core/mock_shopping_service.h"
@@ -54,7 +55,8 @@
     std::vector<chrome_cart::mojom::MerchantCartPtr> found) {
   EXPECT_EQ(1U, found.size());
   EXPECT_EQ(expected_has_utm_source,
-            found[0]->cart_url.spec().find("utm_source") != std::string::npos);
+            found[0]->cart_url.spec().find(commerce::kUTMSourceLabel) !=
+                std::string::npos);
   if (expected_has_utm_source) {
     EXPECT_EQ(expected_has_utm_source,
               found[0]->cart_url.spec().find(
@@ -76,10 +78,14 @@
 
 const char kFakeMerchantKey[] = "Fake:foo.com";
 const char kFakeMerchant[] = "foo.com";
-const char kFakeMerchantURL[] = "https://www.foo.com";
+const char kFakeMerchantURL[] =
+    "https://www.foo.com/"
+    "?utm_source=chrome&utm_medium=app&utm_campaign=chrome-cart";
 const char kMockMerchantBKey[] = "bar.com";
 const char kMockMerchantB[] = "bar.com";
-const char kMockMerchantURLB[] = "https://www.bar.com";
+const char kMockMerchantURLB[] =
+    "https://www.bar.com/"
+    "?utm_source=chrome&utm_medium=app&utm_campaign=chrome-cart";
 const cart_db::ChromeCartContentProto kFakeProto =
     BuildProto(kFakeMerchantKey, kFakeMerchant, kFakeMerchantURL);
 const cart_db::ChromeCartContentProto kMockProtoB =
@@ -99,10 +105,7 @@
       : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP),
         fake_merchant_url_(kFakeMerchantURL),
         mock_merchant_url_(kMockMerchantURLB) {
-    feature_list_.InitAndEnableFeatureWithParameters(
-        ntp_features::kNtpChromeCartModule,
-        {{ntp_features::kNtpChromeCartModuleAbandonedCartDiscountUseUtmParam,
-          "false"}});
+    feature_list_.InitAndEnableFeature(ntp_features::kNtpChromeCartModule);
   }
 
   void SetUp() override {
@@ -443,9 +446,7 @@
     // if a feature is enabled.
     feature_list_.InitAndEnableFeatureWithParameters(
         ntp_features::kNtpChromeCartModule,
-        {{"NtpChromeCartModuleDataParam", "fake"},
-         {ntp_features::kNtpChromeCartModuleAbandonedCartDiscountUseUtmParam,
-          "false"}});
+        {{"NtpChromeCartModuleDataParam", "fake"}});
   }
 
  private:
@@ -491,9 +492,7 @@
     // if a feature is enabled.
     feature_list_.InitAndEnableFeatureWithParameters(
         ntp_features::kNtpChromeCartModule,
-        {{"NtpChromeCartModuleAbandonedCartDiscountParam", "true"},
-         {ntp_features::kNtpChromeCartModuleAbandonedCartDiscountUseUtmParam,
-          "false"}});
+        {{"NtpChromeCartModuleAbandonedCartDiscountParam", "true"}});
   }
 
   void SetUp() override {
@@ -702,9 +701,7 @@
     // if a feature is enabled.
     feature_list_.InitAndEnableFeatureWithParameters(
         ntp_features::kNtpChromeCartModule,
-        {{"NtpChromeCartModuleAbandonedCartDiscountParam", "true"},
-         {ntp_features::kNtpChromeCartModuleAbandonedCartDiscountUseUtmParam,
-          "true"}});
+        {{"NtpChromeCartModuleAbandonedCartDiscountParam", "true"}});
   }
 
   void SetUp() override {
diff --git a/chrome/browser/cart/cart_service.cc b/chrome/browser/cart/cart_service.cc
index a779e25d..9980520 100644
--- a/chrome/browser/cart/cart_service.cc
+++ b/chrome/browser/cart/cart_service.cc
@@ -25,6 +25,7 @@
 #include "chrome/grit/browser_resources.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/autofill/core/browser/data_model/autofill_offer_data.h"
+#include "components/commerce/core/commerce_constants.h"
 #include "components/commerce/core/commerce_feature_list.h"
 #include "components/commerce/core/commerce_heuristics_data.h"
 #include "components/commerce/core/commerce_heuristics_data_metrics_helper.h"
@@ -47,11 +48,6 @@
 
 namespace {
 constexpr char kFakeDataPrefix[] = "Fake:";
-constexpr char kUTMSourceTag[] = "chrome";
-constexpr char kUTMMediumTag[] = "app";
-constexpr char kUTMCampaignChromeCartTag[] = "chrome-cart";
-constexpr char kUTMCampaignDiscountTag[] = "chrome-cart-discount-on";
-constexpr char kUTMCampaignNoDiscountTag[] = "chrome-cart-discount-off";
 constexpr char kCartPrefsKey[] = "chrome_cart";
 
 constexpr base::FeatureParam<std::string> kSkipCartExtractionPattern{
@@ -59,10 +55,6 @@
     // This regex does not match anything.
     "\\b\\B"};
 
-constexpr base::FeatureParam<bool> kRbdUtmParam{
-    &ntp_features::kNtpChromeCartModule,
-    ntp_features::kNtpChromeCartModuleAbandonedCartDiscountUseUtmParam, true};
-
 constexpr base::FeatureParam<bool> kBypassDisocuntFetchingThreshold{
     &commerce::kCommerceDeveloper, "bypass-discount-fetching-threshold", false};
 
@@ -329,19 +321,20 @@
 
 const GURL CartService::AppendUTM(const GURL& base_url) {
   DCHECK(base_url.is_valid());
-  if (!kRbdUtmParam.Get())
-    return base_url;
   auto url = base_url;
-  url = net::AppendOrReplaceQueryParameter(url, "utm_source", kUTMSourceTag);
-  url = net::AppendOrReplaceQueryParameter(url, "utm_medium", kUTMMediumTag);
+  url = net::AppendOrReplaceQueryParameter(url, commerce::kUTMSourceLabel,
+                                           commerce::kUTMSourceValue);
+  url = net::AppendOrReplaceQueryParameter(url, commerce::kUTMMediumLabel,
+                                           commerce::kUTMMediumValue);
   if (commerce::IsPartnerMerchant(base_url)) {
-    return net::AppendOrReplaceQueryParameter(url, "utm_campaign",
-                                              IsCartDiscountEnabled()
-                                                  ? kUTMCampaignDiscountTag
-                                                  : kUTMCampaignNoDiscountTag);
+    return net::AppendOrReplaceQueryParameter(
+        url, commerce::kUTMCampaignLabel,
+        IsCartDiscountEnabled() ? commerce::kUTMCampaignValueForCartDiscount
+                                : commerce::kUTMCampaignValueForCartNoDiscount);
   }
-  return net::AppendOrReplaceQueryParameter(url, "utm_campaign",
-                                            kUTMCampaignChromeCartTag);
+  return net::AppendOrReplaceQueryParameter(
+      url, commerce::kUTMCampaignLabel,
+      commerce::kUTMCampaignValueForChromeCart);
 }
 
 void CartService::HasActiveCartForURL(const GURL& url,
@@ -665,6 +658,9 @@
                                 const history::DeletionInfo& deletion_info) {
   // TODO(crbug.com/1157892): Add more fine-grained deletion of cart data when
   // history deletion happens.
+  if (deletion_info.is_from_expiration()) {
+    return;
+  }
   cart_db_->DeleteAllCarts(base::BindOnce(&CartService::OnOperationFinished,
                                           weak_ptr_factory_.GetWeakPtr()));
   coupon_service_->DeleteAllFreeListingCoupons();
diff --git a/chrome/browser/cart/cart_service_unittest.cc b/chrome/browser/cart/cart_service_unittest.cc
index 50fa166..badf956 100644
--- a/chrome/browser/cart/cart_service_unittest.cc
+++ b/chrome/browser/cart/cart_service_unittest.cc
@@ -117,10 +117,19 @@
 constexpr char kFakeDataPrefix[] = "Fake:";
 const char kMockMerchantA[] = "foo.com";
 const char kMockMerchantURLA[] = "https://www.foo.com";
+const char kMockMerchantURLWithDiscountUtmA[] =
+    "https://www.foo.com/"
+    "?utm_source=chrome&utm_medium=app&utm_campaign=chrome-cart-discount-on";
+const char kMockMerchantURLWithNoDiscountUtmA[] =
+    "https://www.foo.com/"
+    "?utm_source=chrome&utm_medium=app&utm_campaign=chrome-cart-discount-off";
 const char kMockMerchantB[] = "bar.com";
 const char kMockMerchantURLB[] = "https://www.bar.com";
 const char kMockMerchantC[] = "baz.com";
 const char kMockMerchantURLC[] = "https://www.baz.com";
+const char kMockMerchantURLWithCartUtmC[] =
+    "https://www.baz.com/"
+    "?utm_source=chrome&utm_medium=app&utm_campaign=chrome-cart";
 const char kNoDiscountMerchant[] = "nodiscount.com";
 const char kNoDiscountMerchantURL[] = "https://www.nodiscount.com";
 const char kProductURL[] = "https://www.product.com";
@@ -1711,9 +1720,6 @@
     base::FieldTrialParams cart_params, coupon_params, code_based_rbd_param;
     cart_params[ntp_features::kNtpChromeCartModuleAbandonedCartDiscountParam] =
         "true";
-    cart_params
-        [ntp_features::kNtpChromeCartModuleAbandonedCartDiscountUseUtmParam] =
-            "false";
 
     enabled_features.emplace_back(ntp_features::kNtpChromeCartModule,
                                   cart_params);
@@ -1844,14 +1850,14 @@
   base::RunLoop run_loop[2];
   SetCartDiscountURLForTesting(GURL("https://www.discount.com"), false);
   cart_db::ChromeCartContentProto cart_proto =
-      BuildProto(kMockMerchantB, kMockMerchantURLB);
+      BuildProto(kMockMerchantC, kMockMerchantURLC);
   service_->GetDB()->AddCart(
-      kMockMerchantB, cart_proto,
+      kMockMerchantC, cart_proto,
       base::BindOnce(&CartServiceTest::OperationEvaluation,
                      base::Unretained(this), run_loop[0].QuitClosure(), true));
   run_loop[0].Run();
 
-  GURL default_cart_url(kMockMerchantURLB);
+  GURL default_cart_url(kMockMerchantURLWithCartUtmC);
   service_->GetDiscountURL(
       default_cart_url,
       base::BindOnce(&CartServiceTest::GetEvaluationDiscountURL,
@@ -1874,7 +1880,7 @@
                      base::Unretained(this), run_loop[0].QuitClosure()));
   run_loop[0].Run();
 
-  GURL default_cart_url(kMockMerchantURLA);
+  GURL default_cart_url(kMockMerchantURLWithDiscountUtmA);
   service_->GetDiscountURL(
       default_cart_url,
       base::BindOnce(&CartServiceTest::GetEvaluationDiscountURL,
@@ -1904,7 +1910,7 @@
                      base::Unretained(this), run_loop[0].QuitClosure(), true));
   run_loop[0].Run();
 
-  GURL default_cart_url(kMockMerchantURLA);
+  GURL default_cart_url(kMockMerchantURLWithNoDiscountUtmA);
   service_->GetDiscountURL(
       default_cart_url,
       base::BindOnce(&CartServiceTest::GetEvaluationDiscountURL,
@@ -1932,7 +1938,7 @@
                      base::Unretained(this), run_loop[0].QuitClosure(), true));
   run_loop[0].Run();
 
-  GURL default_cart_url(kMockMerchantURLA);
+  GURL default_cart_url(kMockMerchantURLWithDiscountUtmA);
   service_->GetDiscountURL(
       default_cart_url,
       base::BindOnce(&CartServiceTest::GetEvaluationDiscountURL,
@@ -1954,7 +1960,7 @@
   GURL discount_url("https://www.discount.com");
   SetCartDiscountURLForTesting(discount_url, /*expect_call=*/false);
   cart_db::ChromeCartContentProto cart_proto = AddCouponDiscountToProto(
-      BuildProto(kMockMerchantA, kMockMerchantURLA), timestamp,
+      BuildProto(kMockMerchantA, kMockMerchantURLWithDiscountUtmA), timestamp,
       /*discount_text=*/"10% off", kMockMerchantADiscountPromoId);
   service_->GetDB()->AddCart(
       kMockMerchantA, cart_proto,
@@ -1970,7 +1976,7 @@
                                      run_loop[1].QuitClosure(), expected));
   run_loop[1].Run();
 
-  GURL default_cart_url(kMockMerchantURLA);
+  GURL default_cart_url(kMockMerchantURLWithDiscountUtmA);
   service_->GetDiscountURL(
       default_cart_url,
       base::BindOnce(&CartServiceTest::GetEvaluationDiscountURL,
@@ -1987,7 +1993,7 @@
 TEST_F(CartServiceDiscountTest, TestReturnDiscountURL) {
   base::RunLoop run_loop[4];
   const double timestamp = 1;
-  GURL discount_url("https://www.foo.com/discounted");
+  GURL discount_url(kMockMerchantURLWithDiscountUtmA);
   SetCartDiscountURLForTesting(discount_url, true);
   EXPECT_FALSE(service_->IsDiscountUsed(kMockMerchantADiscountRuleId));
   cart_db::ChromeCartContentProto cart_proto = AddDiscountToProto(
@@ -2042,7 +2048,7 @@
                      base::Unretained(this), run_loop[0].QuitClosure(), true));
   run_loop[0].Run();
 
-  GURL default_cart_url(kMockMerchantURLA);
+  GURL default_cart_url(kMockMerchantURLWithDiscountUtmA);
   service_->GetDiscountURL(
       default_cart_url,
       base::BindOnce(&CartServiceTest::GetEvaluationDiscountURL,
@@ -2371,8 +2377,7 @@
     // if a feature is enabled.
     features_.InitAndEnableFeatureWithParameters(
         ntp_features::kNtpChromeCartModule,
-        {{ntp_features::kNtpChromeCartModuleAbandonedCartDiscountParam, "true"},
-         {ntp_features::kNtpChromeCartModuleAbandonedCartDiscountUseUtmParam,
+        {{ntp_features::kNtpChromeCartModuleAbandonedCartDiscountParam,
           "true"}});
   }
   void SetUp() override {
@@ -2394,50 +2399,36 @@
 
 TEST_F(CartServiceCartURLUTMTest, TestAppendUTMForPartnerMerchants) {
   EXPECT_FALSE(service_->IsCartDiscountEnabled());
-  EXPECT_EQ(GURL("https://"
-                 "www.foo.com?utm_source=chrome&utm_medium=app&utm_campaign="
-                 "chrome-cart-discount-off"),
+  EXPECT_EQ(GURL(kMockMerchantURLWithNoDiscountUtmA),
             service_->AppendUTM(GURL(kMockMerchantURLA)));
 
   profile_->GetPrefs()->SetBoolean(prefs::kCartDiscountEnabled, true);
   EXPECT_TRUE(service_->IsCartDiscountEnabled());
-  EXPECT_EQ(GURL("https://"
-                 "www.foo.com?utm_source=chrome&utm_medium=app&utm_campaign="
-                 "chrome-cart-discount-on"),
+  EXPECT_EQ(GURL(kMockMerchantURLWithDiscountUtmA),
             service_->AppendUTM(GURL(kMockMerchantURLA)));
 }
 
 TEST_F(CartServiceCartURLUTMTest, TestAppendUTMForNonPartnerMerchants) {
   EXPECT_FALSE(service_->IsCartDiscountEnabled());
-  EXPECT_EQ(GURL("https://"
-                 "www.bar.com?utm_source=chrome&utm_medium=app&utm_campaign="
-                 "chrome-cart"),
-            service_->AppendUTM(GURL(kMockMerchantURLB)));
+  EXPECT_EQ(GURL(kMockMerchantURLWithCartUtmC),
+            service_->AppendUTM(GURL(kMockMerchantURLC)));
 
   profile_->GetPrefs()->SetBoolean(prefs::kCartDiscountEnabled, true);
   EXPECT_TRUE(service_->IsCartDiscountEnabled());
-  EXPECT_EQ(GURL("https://"
-                 "www.bar.com?utm_source=chrome&utm_medium=app&utm_campaign="
-                 "chrome-cart"),
-            service_->AppendUTM(GURL(kMockMerchantURLB)));
+  EXPECT_EQ(GURL(kMockMerchantURLWithCartUtmC),
+            service_->AppendUTM(GURL(kMockMerchantURLC)));
 }
 
 TEST_F(CartServiceCartURLUTMTest, TestAppendUTMAvoidDuplicates) {
-  GURL merchantUrl = GURL("https://www.foo.com");
+  GURL merchantUrl = GURL(kMockMerchantURLA);
   EXPECT_FALSE(service_->IsCartDiscountEnabled());
   merchantUrl = service_->AppendUTM(GURL(merchantUrl));
-  EXPECT_EQ(GURL("https://"
-                 "www.foo.com?utm_source=chrome&utm_medium=app&utm_campaign="
-                 "chrome-cart-discount-off"),
-            merchantUrl);
+  EXPECT_EQ(GURL(kMockMerchantURLWithNoDiscountUtmA), merchantUrl);
 
   profile_->GetPrefs()->SetBoolean(prefs::kCartDiscountEnabled, true);
   EXPECT_TRUE(service_->IsCartDiscountEnabled());
   merchantUrl = service_->AppendUTM(GURL(merchantUrl));
-  EXPECT_EQ(GURL("https://"
-                 "www.foo.com?utm_source=chrome&utm_medium=app&utm_campaign="
-                 "chrome-cart-discount-on"),
-            merchantUrl);
+  EXPECT_EQ(GURL(kMockMerchantURLWithDiscountUtmA), merchantUrl);
 }
 
 class FakeFetchDiscountWorker : public FetchDiscountWorker {
diff --git a/chrome/browser/extensions/api/offscreen/offscreen_apitest.cc b/chrome/browser/extensions/api/offscreen/offscreen_apitest.cc
index 25eee9b..e881726 100644
--- a/chrome/browser/extensions/api/offscreen/offscreen_apitest.cc
+++ b/chrome/browser/extensions/api/offscreen/offscreen_apitest.cc
@@ -685,6 +685,56 @@
   }
 };
 
+// Tests opening an offscreen document that takes awhile to load properly waits
+// for the document to load before resolving the promise, ensuring the document
+// is ready to receive messages by the time the promise resolves.
+IN_PROC_BROWSER_TEST_F(OffscreenApiTest, LongLoadOffscreenDocument) {
+  static constexpr char kManifest[] =
+      R"({
+           "name": "Offscreen Document Test",
+           "manifest_version": 3,
+           "version": "0.1",
+           "permissions": ["offscreen"],
+           "background": { "service_worker": "background.js" }
+         })";
+  static constexpr char kOffscreenHtml[] =
+      R"(<html><script src="offscreen.js"></script></html>)";
+  // This script busy-waits for two seconds before (synchronously) adding a
+  // message listener.
+  static constexpr char kOffscreenJs[] =
+      R"(const startTime = performance.now();
+         const endTime = startTime + 2000;
+         while (performance.now() < endTime) { /* Spin our wheels! */ }
+         chrome.runtime.onMessage.addListener((msg, sender, reply) => {
+           reply(msg + ' reply');
+         });)";
+  // The background script will open an offscreen document and, once the
+  // createDocument() call resolves, send a message. Since createDocument()
+  // should wait for document to finish loading, this should work.
+  static constexpr char kBackgroundJs[] =
+      R"(chrome.test.runTests([
+           async function longLoadDocAndSendMessage() {
+             await chrome.offscreen.createDocument(
+                       {
+                           url: 'offscreen.html',
+                           reasons: ['TESTING'],
+                           justification: 'testing'
+                       });
+             const reply = await chrome.runtime.sendMessage('test message');
+             chrome.test.assertEq('test message reply', reply);
+             chrome.test.succeed();
+           },
+         ]);)";
+
+  TestExtensionDir test_dir;
+  test_dir.WriteManifest(kManifest);
+  test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), kBackgroundJs);
+  test_dir.WriteFile(FILE_PATH_LITERAL("offscreen.html"), kOffscreenHtml);
+  test_dir.WriteFile(FILE_PATH_LITERAL("offscreen.js"), kOffscreenJs);
+
+  ASSERT_TRUE(RunExtensionTest(test_dir.UnpackedPath(), {}, {})) << message_;
+}
+
 // Tests that the `TESTING` reason is disallowed without the appropriate
 // commandline switch.
 IN_PROC_BROWSER_TEST_F(OffscreenApiTestWithoutCommandLineFlag,
diff --git a/chrome/browser/extensions/api/permissions/permissions_apitest.cc b/chrome/browser/extensions/api/permissions/permissions_apitest.cc
index 25ae583..932adb47 100644
--- a/chrome/browser/extensions/api/permissions/permissions_apitest.cc
+++ b/chrome/browser/extensions/api/permissions/permissions_apitest.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include "base/files/file_util.h"
-#include "base/test/metrics/histogram_tester.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/extensions/api/permissions/permissions_api.h"
@@ -108,10 +107,7 @@
 #define MAYBE_FaviconPermission FaviconPermission
 #endif
 IN_PROC_BROWSER_TEST_F(PermissionsApiTest, MAYBE_FaviconPermission) {
-  base::HistogramTester tester;
   ASSERT_TRUE(RunExtensionTest("permissions/favicon")) << message_;
-  tester.ExpectBucketCount("Extensions.FaviconResourceRequested",
-                           Manifest::TYPE_EXTENSION, 1);
 }
 
 // Test functions and APIs that are always allowed (even if you ask for no
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 1c7eb7b..432ba53 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1095,6 +1095,11 @@
     "expiry_milestone": 130
   },
   {
+    "name": "cct-page-insights-hub-better-scroll",
+    "owners": [ "jinsukkim@chromium.org", "kgrosu@google.com", "twellington@chromium.org" ],
+    "expiry_milestone": 130
+  },
+  {
     "name": "cct-prevent-touches",
     "owners": [ "jinsukkim@chromium.org", "kgrosu@google.com", "twellington@chromium.org" ],
     "expiry_milestone": 140
@@ -2978,11 +2983,6 @@
     "expiry_milestone": 140
   },
   {
-    "name": "enable-lens-image-format-optimizations",
-    "owners": ["mercerd@google.com", "stanfield@google.com", "lens-chrome@google.com"],
-    "expiry_milestone": 120
-  },
-  {
     "name": "enable-lens-image-translate",
     "owners": ["nguyenbryan@google.com", "stanfield@google.com", "lens-chrome@google.com"],
     "expiry_milestone": 120
@@ -6275,11 +6275,6 @@
     "expiry_milestone": 121
   },
   {
-    "name": "password-edit-dialog-with-details",
-    "owners": ["atsvirchkova@google.com", "ioanap@chromium.org"],
-    "expiry_milestone": 112
-  },
-  {
     "name": "password-generation-bottom-sheet",
     "owners": ["atsvirchkova@google.com", "ioanap@chromium.org"],
     "expiry_milestone": 123
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 8e1ef13..ac4fefc 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2204,11 +2204,6 @@
     "Enables use of a static page in a new tab when using the Lens region "
     "search feature.";
 
-const char kLensImageFormatOptimizationsName[] = "Lens Optimized Image Formats";
-const char kLensImageFormatOptimizationsDescription[] =
-    "Enables the use of either WebP or JPEG on all Lens quries to reduce "
-    "network load and improve latency";
-
 const char kLensImageTranslateName[] =
     "Translate text in images with Google Lens";
 const char kLensImageTranslateDescription[] =
@@ -3893,6 +3888,11 @@
 const char kCCTPageInsightsHubDescription[] =
     "Show Page Insights Hub on Chrome Custom Tabs.";
 
+const char kCCTPageInsightsHubBetterScrollName[] =
+    "Page Insights Hub Scroll improvement";
+const char kCCTPageInsightsHubBetterScrollDescription[] =
+    "Resize Web content in sync with Page Insights sheet.";
+
 const char kCCTResizableForThirdPartiesName[] =
     "Bottom sheet Custom Tabs (third party)";
 const char kCCTResizableForThirdPartiesDescription[] =
@@ -4090,9 +4090,6 @@
 const char kInterestFeedV2HeartsName[] = "Interest Feed v2 Hearts";
 const char kInterestFeedV2HeartsDescription[] = "Enable hearts on Feedv2.";
 
-const char kInterestFeedV2AutoplayName[] = "Interest Feed v2 Autoplay";
-const char kInterestFeedV2AutoplayDescription[] = "Enable autoplay on Feedv2.";
-
 const char kMediaPickerAdoptionStudyName[] = "Android Media Picker Adoption";
 const char kMediaPickerAdoptionStudyDescription[] =
     "Controls how to launch the Android Media Picker (note: This flag is "
@@ -4164,12 +4161,6 @@
     "flow. "
     "Only works with builds targeting Android T+.";
 
-const char kOfflinePagesLivePageSharingName[] =
-    "Enables live page sharing of offline pages";
-const char kOfflinePagesLivePageSharingDescription[] =
-    "Enables to share current loaded page as offline page by saving as MHTML "
-    "first.";
-
 const char kPageInfoHistoryName[] = "Page info history";
 const char kPageInfoHistoryDescription[] =
     "Enable a history sub page to the page info menu, and a button to forget "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 92c6410..acba0d3 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -2253,6 +2253,9 @@
 extern const char kCCTPageInsightsHubName[];
 extern const char kCCTPageInsightsHubDescription[];
 
+extern const char kCCTPageInsightsHubBetterScrollName[];
+extern const char kCCTPageInsightsHubBetterScrollDescription[];
+
 extern const char kCCTResizableForThirdPartiesName[];
 extern const char kCCTResizableForThirdPartiesDescription[];
 extern const char kCCTResizableSideSheetName[];
@@ -2388,9 +2391,6 @@
 extern const char kInterestFeedV2HeartsName[];
 extern const char kInterestFeedV2HeartsDescription[];
 
-extern const char kInterestFeedV2AutoplayName[];
-extern const char kInterestFeedV2AutoplayDescription[];
-
 extern const char kMediaPickerAdoptionStudyName[];
 extern const char kMediaPickerAdoptionStudyDescription[];
 
@@ -2433,9 +2433,6 @@
 extern const char kNotificationPermissionRationaleBottomSheetName[];
 extern const char kNotificationPermissionRationaleBottomSheetDescription[];
 
-extern const char kOfflinePagesLivePageSharingName[];
-extern const char kOfflinePagesLivePageSharingDescription[];
-
 extern const char kOmahaMinSdkVersionAndroidName[];
 extern const char kOmahaMinSdkVersionAndroidDescription[];
 extern const char kOmahaMinSdkVersionAndroidMinSdk1Description[];
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index bd9fa27..6ff0e2f 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -138,7 +138,6 @@
     &feed::kFeedSignedOutViewDemotion,
     &feed::kFeedUserInteractionReliabilityReport,
     &feed::kInterestFeedV2,
-    &feed::kInterestFeedV2Autoplay,
     &feed::kInterestFeedV2Hearts,
     &feed::kWebFeed,
     &feed::kWebFeedAwareness,
@@ -186,12 +185,12 @@
     &kCCTIntentFeatureOverrides,
     &kCCTMinimized,
     &kCCTPageInsightsHub,
+    &kCCTPageInsightsHubBetterScroll,
     &kCCTRealTimeEngagementSignals,
     &kCCTReportParallelRequestStatus,
     &kCCTResizableForThirdParties,
     &kCCTResizableSideSheet,
     &kCCTResizableSideSheetForThirdParties,
-    &kCCTResourcePrefetch,
     &kCCTTabModalDialog,
     &kDontAutoHideBrowserControls,
     &kCacheDeprecatedSystemLocationSetting,
@@ -301,7 +300,6 @@
     &kWebApkAllowIconUpdate,
     &kWebApkBackupAndRestoreBackend,
     &kWebApkIconUpdateThreshold,
-    &kWebApkInstallService,
     &features::kDnsOverHttps,
     &notifications::features::kUseChimeAndroidSdk,
     &paint_preview::kPaintPreviewDemo,
@@ -312,7 +310,6 @@
     &offline_pages::kOfflinePagesCTFeature,  // See crbug.com/620421.
     &offline_pages::kOfflinePagesDescriptiveFailStatusFeature,
     &offline_pages::kOfflinePagesDescriptivePendingStatusFeature,
-    &offline_pages::kOfflinePagesLivePageSharingFeature,
     &omnibox::kMostVisitedTilesHorizontalRenderGroup,
     &omnibox::kOmniboxMatchToolbarAndStatusBarColor,
     &omnibox::kOmniboxModernizeVisualUpdate,
@@ -516,6 +513,10 @@
              "CCTPageInsightsHub",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kCCTPageInsightsHubBetterScroll,
+             "CCTPageInsightsHubBetterScroll",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 BASE_FEATURE(kCCTRealTimeEngagementSignals,
              "CCTRealTimeEngagementSignals",
              base::FEATURE_ENABLED_BY_DEFAULT);
@@ -536,10 +537,6 @@
              "CCTResizableSideSheetForThirdParties",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
-BASE_FEATURE(kCCTResourcePrefetch,
-             "CCTResourcePrefetch",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 BASE_FEATURE(kCCTTabModalDialog,
              "CCTTabModalDialog",
              base::FEATURE_ENABLED_BY_DEFAULT);
@@ -998,10 +995,5 @@
              "WebApkBackupAndRestoreBackend",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// Enables the Chrome Android WebAPK-install service.
-BASE_FEATURE(kWebApkInstallService,
-             "WebApkInstallService",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 }  // namespace android
 }  // namespace chrome
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h
index ef23f22..c1d817e 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -49,13 +49,13 @@
 BASE_DECLARE_FEATURE(kCCTIntentFeatureOverrides);
 BASE_DECLARE_FEATURE(kCCTMinimized);
 BASE_DECLARE_FEATURE(kCCTPageInsightsHub);
+BASE_DECLARE_FEATURE(kCCTPageInsightsHubBetterScroll);
 BASE_DECLARE_FEATURE(kCCTPrefetchDelayShowOnStart);
 BASE_DECLARE_FEATURE(kCCTRealTimeEngagementSignals);
 BASE_DECLARE_FEATURE(kCCTReportParallelRequestStatus);
 BASE_DECLARE_FEATURE(kCCTResizableForThirdParties);
 BASE_DECLARE_FEATURE(kCCTResizableSideSheet);
 BASE_DECLARE_FEATURE(kCCTResizableSideSheetForThirdParties);
-BASE_DECLARE_FEATURE(kCCTResourcePrefetch);
 BASE_DECLARE_FEATURE(kCCTRetainingStateInMemory);
 BASE_DECLARE_FEATURE(kCCTTabModalDialog);
 BASE_DECLARE_FEATURE(kDontAutoHideBrowserControls);
@@ -181,7 +181,6 @@
 BASE_DECLARE_FEATURE(kWebApkAllowIconUpdate);
 BASE_DECLARE_FEATURE(kWebApkBackupAndRestoreBackend);
 BASE_DECLARE_FEATURE(kWebApkIconUpdateThreshold);
-BASE_DECLARE_FEATURE(kWebApkInstallService);
 
 // For FeatureParam, Alphabetical:
 constexpr base::FeatureParam<int> kAuxiliarySearchMaxBookmarksCountParam(
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index 21dd3ad..389e3e1 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -179,6 +179,8 @@
     public static final String CCT_MINIMIZED = "CCTMinimized";
     public static final String CCT_INTENT_FEATURE_OVERRIDES = "CCTIntentFeatureOverrides";
     public static final String CCT_PAGE_INSIGHTS_HUB = "CCTPageInsightsHub";
+    public static final String CCT_PAGE_INSIGHTS_HUB_BETTER_SCROLL =
+            "CCTPageInsightsHubBetterScroll";
     public static final String CCT_REAL_TIME_ENGAGEMENT_SIGNALS = "CCTRealTimeEngagementSignals";
     public static final String CCT_REPORT_PARALLEL_REQUEST_STATUS =
             "CCTReportParallelRequestStatus";
@@ -186,7 +188,6 @@
     public static final String CCT_RESIZABLE_SIDE_SHEET = "CCTResizableSideSheet";
     public static final String CCT_RESIZABLE_SIDE_SHEET_FOR_THIRD_PARTIES =
             "CCTResizableSideSheetForThirdParties";
-    public static final String CCT_RESOURCE_PREFETCH = "CCTResourcePrefetch";
     public static final String CCT_TAB_MODAL_DIALOG = "CCTTabModalDialog";
     public static final String CHROME_SURVEY_NEXT_ANDROID = "ChromeSurveyNextAndroid";
     public static final String CLEAR_OMNIBOX_FOCUS_AFTER_NAVIGATION =
@@ -278,7 +279,6 @@
     public static final String INCOGNITO_SCREENSHOT = "IncognitoScreenshot";
     public static final String INSTALLABLE_AMBIENT_BADGE_MESSAGE = "InstallableAmbientBadgeMessage";
     public static final String INSTANT_START = "InstantStart";
-    public static final String INTEREST_FEED_V2_AUTOPLAY = "InterestFeedV2Autoplay";
     public static final String INTEREST_FEED_V2_HEARTS = "InterestFeedV2Hearts";
     public static final String KID_FRIENDLY_CONTENT_FEED = "KidFriendlyContentFeed";
     public static final String LENS_CAMERA_ASSISTED_SEARCH = "LensCameraAssistedSearch";
@@ -298,7 +298,6 @@
             "OfflinePagesDescriptiveFailStatus";
     public static final String OFFLINE_PAGES_DESCRIPTIVE_PENDING_STATUS =
             "OfflinePagesDescriptivePendingStatus";
-    public static final String OFFLINE_PAGES_LIVE_PAGE_SHARING = "OfflinePagesLivePageSharing";
     public static final String OMAHA_MIN_SDK_VERSION_ANDROID = "OmahaMinSdkVersionAndroid";
     public static final String OMNIBOX_CACHE_SUGGESTION_RESOURCES =
             "OmniboxCacheSuggestionResources";
@@ -457,7 +456,6 @@
     public static final String VOICE_SEARCH_AUDIO_CAPTURE_POLICY = "VoiceSearchAudioCapturePolicy";
     public static final String WEB_APK_ALLOW_ICON_UPDATE = "WebApkAllowIconUpdate";
     public static final String WEB_APK_ICON_UPDATE_THRESHOLD = "WebApkIconUpdateThreshold";
-    public static final String WEB_APK_INSTALL_SERVICE = "WebApkInstallService";
     public static final String WEB_APP_AMBIENT_BADGE_SUPRESS_FIRST_VISIT =
             "AmbientBadgeSuppressFirstVisit";
     public static final String WEB_APK_INSTALL_FAILURE_NOTIFICATION =
@@ -706,6 +704,8 @@
             newMutableFlagWithSafeDefault(OMNIBOX_HISTORY_CLUSTER_PROVIDER, false);
     public static final MutableFlagWithSafeDefault sOmniboxNoopEditUrlSuggestionClicks =
             newMutableFlagWithSafeDefault(OMNIBOX_NOOP_EDIT_URL_SUGGESTION_CLICKS, false);
+    public static final MutableFlagWithSafeDefault sPageInsightsResizeInSync =
+            newMutableFlagWithSafeDefault(CCT_PAGE_INSIGHTS_HUB_BETTER_SCROLL, false);
     public static final MutableFlagWithSafeDefault sQuickDeleteForAndroid =
             newMutableFlagWithSafeDefault(QUICK_DELETE_FOR_ANDROID, false);
     public static final MutableFlagWithSafeDefault sReaderModeCct =
diff --git a/chrome/browser/gesturenav/android/tab_on_back_gesture_handler.cc b/chrome/browser/gesturenav/android/tab_on_back_gesture_handler.cc
index cc72ddc..63bdcb7 100644
--- a/chrome/browser/gesturenav/android/tab_on_back_gesture_handler.cc
+++ b/chrome/browser/gesturenav/android/tab_on_back_gesture_handler.cc
@@ -21,10 +21,10 @@
                                             float progress,
                                             int edge,
                                             bool forward) {
-  CHECK(!is_in_progress_, base::NotFatalUntil::M122);
+  CHECK(!is_in_progress_, base::NotFatalUntil::M123);
   is_in_progress_ = true;
   content::WebContents* web_contents = tab_android_->web_contents();
-  CHECK(web_contents, base::NotFatalUntil::M122);
+  CHECK(web_contents, base::NotFatalUntil::M123);
   ui::BackGestureEvent backEvent(gfx::PointF(x, y), progress);
   started_edge_ = static_cast<ui::BackGestureEventSwipeEdge>(edge);
 }
@@ -34,18 +34,18 @@
                                                float y,
                                                float progress,
                                                int edge) {
-  CHECK(is_in_progress_, base::NotFatalUntil::M122);
+  CHECK(is_in_progress_, base::NotFatalUntil::M123);
   CHECK_EQ(started_edge_, static_cast<ui::BackGestureEventSwipeEdge>(edge));
   ui::BackGestureEvent backEvent(gfx::PointF(x, y), progress);
 }
 
 void TabOnBackGestureHandler::OnBackCancelled(JNIEnv* env) {
-  CHECK(is_in_progress_, base::NotFatalUntil::M122);
+  CHECK(is_in_progress_, base::NotFatalUntil::M123);
   is_in_progress_ = false;
 }
 
 void TabOnBackGestureHandler::OnBackInvoked(JNIEnv* env) {
-  CHECK(is_in_progress_, base::NotFatalUntil::M122);
+  CHECK(is_in_progress_, base::NotFatalUntil::M123);
   is_in_progress_ = false;
 }
 
diff --git a/chrome/browser/net/network_quality_estimator_prefs_browsertest.cc b/chrome/browser/net/network_quality_estimator_prefs_browsertest.cc
index 4c2a577..38ff871 100644
--- a/chrome/browser/net/network_quality_estimator_prefs_browsertest.cc
+++ b/chrome/browser/net/network_quality_estimator_prefs_browsertest.cc
@@ -15,7 +15,6 @@
 #include "base/process/memory.h"
 #include "base/run_loop.h"
 #include "base/task/deferred_sequenced_task_runner.h"
-#include "base/test/metrics/histogram_tester.h"
 #include "base/test/task_environment.h"
 #include "base/threading/thread_restrictions.h"
 #include "chrome/browser/browser_process.h"
@@ -61,34 +60,6 @@
       ->SimulateNetworkQualityChangeForTesting(type);
 }
 
-// Retries fetching |histogram_name| until it contains at least |count| samples.
-void RetryForHistogramUntilCountReached(base::HistogramTester* histogram_tester,
-                                        const std::string& histogram_name,
-                                        size_t count) {
-  while (true) {
-    const std::vector<base::Bucket> buckets =
-        histogram_tester->GetAllSamples(histogram_name);
-    size_t total_count = 0;
-    for (const auto& bucket : buckets)
-      total_count += bucket.count;
-    if (total_count >= count)
-      return;
-    content::FetchHistogramsFromChildProcesses();
-    metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
-    base::RunLoop().RunUntilIdle();
-  }
-}
-
-int GetHistogramSamplesSum(base::HistogramTester* histogram_tester,
-                           const std::string& histogram_name) {
-  const std::vector<base::Bucket> buckets =
-      histogram_tester->GetAllSamples(histogram_name);
-  size_t sum = 0;
-  for (const auto& bucket : buckets)
-    sum += (bucket.count * bucket.min);
-  return sum;
-}
-
 class TestNetworkQualityObserver
     : public network::NetworkQualityTracker::EffectiveConnectionTypeObserver {
  public:
@@ -171,20 +142,8 @@
                              base::Unretained(&run_loop)));
     run_loop.Run();
   }
-
-  base::HistogramTester histogram_tester;
 };
 
-// Verify that prefs are read at startup, and the read prefs are notified to the
-// network quality estimator.
-IN_PROC_BROWSER_TEST_F(NetworkQualityEstimatorPrefsBrowserTest,
-                       ReadPrefsAtStartup) {
-  // The check below ensures that "NQE.Prefs.ReadSize" contains at least one
-  // sample. This implies that NQE was notified of the read prefs.
-  RetryForHistogramUntilCountReached(&histogram_tester, "NQE.Prefs.ReadSize",
-                                     1);
-}
-
 // Verify that prefs are read at startup.
 // Flaky on ChromeOS. See https://crbug.com/1484891
 #if BUILDFLAG(IS_CHROMEOS)
@@ -196,12 +155,6 @@
 IN_PROC_BROWSER_TEST_F(NetworkQualityEstimatorPrefsBrowserTest,
                        MAYBE_ReadPrefsAtStartupCustomPrefFile) {
   base::ScopedAllowBlockingForTesting scoped_allow_blocking;
-  // The check below ensures that "NQE.Prefs.ReadSize" contains at least one
-  // sample. This implies that NQE was notified of the read prefs.
-  RetryForHistogramUntilCountReached(&histogram_tester, "NQE.Prefs.ReadSize",
-                                     1);
-
-  base::HistogramTester histogram_tester2;
 
   // Create network context with JSON pref store pointing to the temp file.
   mojo::PendingRemote<network::mojom::NetworkContext> network_context;
@@ -237,28 +190,13 @@
   content::CreateNetworkContextInNetworkService(
       network_context.InitWithNewPipeAndPassReceiver(),
       std::move(context_params));
-
-  RetryForHistogramUntilCountReached(&histogram_tester2, "NQE.Prefs.ReadSize",
-                                     1);
-  // Pref value must be read from the temp file.
-  EXPECT_LE(1,
-            GetHistogramSamplesSum(&histogram_tester2, "NQE.Prefs.ReadSize"));
 }
 
 // Verify that prefs are read at startup, and written to later.
 IN_PROC_BROWSER_TEST_F(NetworkQualityEstimatorPrefsBrowserTest, PrefsWritten) {
-  // The check below ensures that "NQE.Prefs.ReadSize" contains at least one
-  // sample. This implies that NQE was notified of the read prefs.
-  RetryForHistogramUntilCountReached(&histogram_tester, "NQE.Prefs.ReadSize",
-                                     1);
-
-  // Change in network quality is guaranteed to trigger a pref write.
   SimulateNetworkQualityChange(net::EFFECTIVE_CONNECTION_TYPE_2G);
   TestNetworkQualityObserver network_quality_observer(
       g_browser_process->network_quality_tracker());
   network_quality_observer.WaitForNotification(
       net::EFFECTIVE_CONNECTION_TYPE_2G);
-
-  RetryForHistogramUntilCountReached(&histogram_tester, "NQE.Prefs.WriteCount",
-                                     1);
 }
diff --git a/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc b/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc
index 76a0202..f0746e8 100644
--- a/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc
+++ b/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc
@@ -429,7 +429,8 @@
           std::make_unique<optimization_guide::ModelExecutionManager>(
               url_loader_factory,
               IdentityManagerFactory::GetForProfile(profile),
-              std::move(service_controller), optimization_guide_logger_.get());
+              std::move(service_controller), this,
+              optimization_guide_logger_.get());
     }
   }
 
diff --git a/chrome/browser/partnercustomizations/junit/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableBookmarksEditingUnitTest.java b/chrome/browser/partnercustomizations/junit/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableBookmarksEditingUnitTest.java
index e0b5a379..939cdce 100644
--- a/chrome/browser/partnercustomizations/junit/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableBookmarksEditingUnitTest.java
+++ b/chrome/browser/partnercustomizations/junit/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableBookmarksEditingUnitTest.java
@@ -21,6 +21,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.partnercustomizations.TestPartnerBrowserCustomizationsDelayedProvider;
@@ -149,6 +150,7 @@
     @Test
     @SmallTest
     @Feature({"PartnerBookmarksEditing"})
+    @DisabledTest(message = "Flaky due to ConcurrentModificationException, crbug.com/1446093")
     public void testBookmarksEditingProviderDelayed() throws InterruptedException {
         CustomizationProviderDelegateUpstreamImpl.setProviderAuthorityForTesting(
                 PARTNER_BROWSER_CUSTOMIZATIONS_DELAYED_PROVIDER);
diff --git a/chrome/browser/password_edit_dialog/android/java/src/org/chromium/chrome/browser/password_edit_dialog/PasswordEditDialogViewTest.java b/chrome/browser/password_edit_dialog/android/java/src/org/chromium/chrome/browser/password_edit_dialog/PasswordEditDialogViewTest.java
index 89071292..c6e7130 100644
--- a/chrome/browser/password_edit_dialog/android/java/src/org/chromium/chrome/browser/password_edit_dialog/PasswordEditDialogViewTest.java
+++ b/chrome/browser/password_edit_dialog/android/java/src/org/chromium/chrome/browser/password_edit_dialog/PasswordEditDialogViewTest.java
@@ -40,7 +40,7 @@
 
 import java.util.Arrays;
 
-/** View tests for PasswordEditDialogWithDetailsView */
+/** View tests for PasswordEditDialogView */
 @RunWith(BaseJUnit4ClassRunner.class)
 @Batch(Batch.PER_CLASS)
 public class PasswordEditDialogViewTest {
diff --git a/chrome/browser/password_edit_dialog/android/password_edit_dialog_bridge.h b/chrome/browser/password_edit_dialog/android/password_edit_dialog_bridge.h
index 910ad713..5157f04 100644
--- a/chrome/browser/password_edit_dialog/android/password_edit_dialog_bridge.h
+++ b/chrome/browser/password_edit_dialog/android/password_edit_dialog_bridge.h
@@ -57,7 +57,6 @@
   virtual ~PasswordEditDialog();
 
   // Calls Java side of the bridge to display password edit modal dialog.
-  // Called when PasswordEditDialogWithDetails feature is enabled.
   virtual void ShowPasswordEditDialog(
       const std::vector<std::u16string>& usernames,
       const std::u16string& username,
@@ -87,7 +86,6 @@
   PasswordEditDialogBridge& operator=(const PasswordEditDialogBridge&) = delete;
 
   // Calls Java side of the bridge to display password edit modal dialog.
-  // Called when PasswordEditDialogWithDetails feature is enabled.
   void ShowPasswordEditDialog(const std::vector<std::u16string>& usernames,
                               const std::u16string& username,
                               const std::u16string& password,
@@ -101,16 +99,10 @@
   // Called from Java to indicate that the user tapped the positive button with
   // |username| and
   // |password| which are going to be saved.
-  // Used when PasswordEditDialogWithDetails flag is on.
   void OnDialogAccepted(JNIEnv* env,
                         const base::android::JavaParamRef<jstring>& username,
                         const base::android::JavaParamRef<jstring>& password);
 
-  // Called from Java to indicate that the user tapped the positive button with
-  // |username_index|.
-  // Used when PasswordEditDialogWithDetails flag is off.
-  void OnLegacyDialogAccepted(JNIEnv* env, jint username_index);
-
   // Called from Java when the modal dialog is dismissed.
   void OnDialogDismissed(JNIEnv* env, jboolean dialogAccepted);
 
diff --git a/chrome/browser/password_manager/android/save_update_password_message_delegate_unittest.cc b/chrome/browser/password_manager/android/save_update_password_message_delegate_unittest.cc
index ed652180..3c4b863 100644
--- a/chrome/browser/password_manager/android/save_update_password_message_delegate_unittest.cc
+++ b/chrome/browser/password_manager/android/save_update_password_message_delegate_unittest.cc
@@ -479,8 +479,7 @@
 }
 
 // Tests that secondary menu icon is set for the save password message
-TEST_F(SaveUpdatePasswordMessageDelegateTest,
-       CogButton_SavePassword_PasswordEditDialogWithDetails) {
+TEST_F(SaveUpdatePasswordMessageDelegateTest, CogButton_SavePassword) {
   SetPendingCredentials(kUsername, kPassword);
   auto form_manager =
       CreateFormManager(GURL(kDefaultUrl), empty_best_matches());
@@ -496,7 +495,7 @@
 // Tests that secondary menu icon is set for the update password message
 // in case when user has only single credential stored for the web site
 TEST_F(SaveUpdatePasswordMessageDelegateTest,
-       CogButton_SingleCredUpdatePassword_PasswordEditDialogWithDetails) {
+       CogButton_SingleCredUpdatePassword) {
   SetPendingCredentials(kUsername, kPassword);
   auto form_manager =
       CreateFormManager(GURL(kDefaultUrl), empty_best_matches());
@@ -512,7 +511,7 @@
 // Tests that secondary menu icon is not set for the update password message
 // in case when user has multiple credentials stored for the web site
 TEST_F(SaveUpdatePasswordMessageDelegateTest,
-       NoCogButton_MultipleCredUpdatePassword_PasswordEditDialogWithDetails) {
+       NoCogButton_MultipleCredUpdatePassword) {
   SetPendingCredentials(kUsername, kPassword);
   auto form_manager =
       CreateFormManager(GURL(kDefaultUrl), two_forms_best_matches());
diff --git a/chrome/browser/performance_manager/metrics/metrics_provider_desktop.cc b/chrome/browser/performance_manager/metrics/metrics_provider_desktop.cc
index 4cd4475..8332d325 100644
--- a/chrome/browser/performance_manager/metrics/metrics_provider_desktop.cc
+++ b/chrome/browser/performance_manager/metrics/metrics_provider_desktop.cc
@@ -135,7 +135,7 @@
   pref_change_registrar_.Init(local_state_);
   pref_change_registrar_.Add(
       kMemorySaverModeState,
-      base::BindRepeating(&MetricsProviderDesktop::OnHighEfficiencyPrefChanged,
+      base::BindRepeating(&MetricsProviderDesktop::OnMemorySaverPrefChanged,
                           base::Unretained(this)));
   performance_manager::user_tuning::BatterySaverModeManager::GetInstance()
       ->AddObserver(this);
@@ -185,8 +185,8 @@
   OnTuningModesChanged();
 }
 
-void MetricsProviderDesktop::OnHighEfficiencyPrefChanged() {
-  high_efficiency_mode_tracker_->ModeChanged(IsHighEfficiencyEnabled());
+void MetricsProviderDesktop::OnMemorySaverPrefChanged() {
+  memory_saver_mode_tracker_->ModeChanged(IsMemorySaverEnabled());
   OnTuningModesChanged();
 }
 
@@ -215,14 +215,14 @@
   // BatterySaverModeManager is destroyed. Do not access UPTM directly from
   // here.
 
-  bool high_efficiency_enabled = IsHighEfficiencyEnabled();
+  bool high_efficiency_enabled = IsMemorySaverEnabled();
 
   if (high_efficiency_enabled && battery_saver_enabled_) {
     return EfficiencyMode::kBoth;
   }
 
   if (high_efficiency_enabled) {
-    return EfficiencyMode::kHighEfficiency;
+    return EfficiencyMode::kMemorySaver;
   }
 
   if (battery_saver_enabled_) {
@@ -232,7 +232,7 @@
   return EfficiencyMode::kNormal;
 }
 
-bool MetricsProviderDesktop::IsHighEfficiencyEnabled() const {
+bool MetricsProviderDesktop::IsMemorySaverEnabled() const {
   return local_state_->GetInteger(kMemorySaverModeState) !=
          static_cast<int>(MemorySaverModeState::kDisabled);
 }
@@ -265,8 +265,8 @@
   battery_saver_mode_tracker_ = std::make_unique<ScopedTimeInModeTracker>(
       battery_saver_enabled_,
       "PerformanceManager.UserTuning.BatterySaverModeEnabledPercent");
-  high_efficiency_mode_tracker_ = std::make_unique<ScopedTimeInModeTracker>(
-      IsHighEfficiencyEnabled(),
+  memory_saver_mode_tracker_ = std::make_unique<ScopedTimeInModeTracker>(
+      IsMemorySaverEnabled(),
       "PerformanceManager.UserTuning.MemorySaverModeEnabledPercent");
 }
 
diff --git a/chrome/browser/performance_manager/metrics/metrics_provider_desktop.h b/chrome/browser/performance_manager/metrics/metrics_provider_desktop.h
index 804faa80..0b04418c 100644
--- a/chrome/browser/performance_manager/metrics/metrics_provider_desktop.h
+++ b/chrome/browser/performance_manager/metrics/metrics_provider_desktop.h
@@ -29,7 +29,7 @@
     // No efficiency mode for the entire upload window
     kNormal = 0,
     // In memory saver mode for the entire upload window
-    kHighEfficiency = 1,
+    kMemorySaver = 1,
     // In battery saver mode for the entire upload window
     kBatterySaver = 2,
     // Both modes enabled for the entire upload window
@@ -60,10 +60,10 @@
   // BatterySaverModeManager::Observer:
   void OnBatterySaverActiveChanged(bool is_active) override;
 
-  void OnHighEfficiencyPrefChanged();
+  void OnMemorySaverPrefChanged();
   void OnTuningModesChanged();
   EfficiencyMode ComputeCurrentMode() const;
-  bool IsHighEfficiencyEnabled() const;
+  bool IsMemorySaverEnabled() const;
 
   void RecordAvailableMemoryMetrics();
   void ResetTrackers();
@@ -79,7 +79,7 @@
   base::RepeatingTimer available_memory_metrics_timer_;
 
   std::unique_ptr<ScopedTimeInModeTracker> battery_saver_mode_tracker_;
-  std::unique_ptr<ScopedTimeInModeTracker> high_efficiency_mode_tracker_;
+  std::unique_ptr<ScopedTimeInModeTracker> memory_saver_mode_tracker_;
 };
 
 }  // namespace performance_manager
diff --git a/chrome/browser/performance_manager/metrics/metrics_provider_desktop_unittest.cc b/chrome/browser/performance_manager/metrics/metrics_provider_desktop_unittest.cc
index 11c1b1ce..38fb1045 100644
--- a/chrome/browser/performance_manager/metrics/metrics_provider_desktop_unittest.cc
+++ b/chrome/browser/performance_manager/metrics/metrics_provider_desktop_unittest.cc
@@ -19,7 +19,7 @@
  protected:
   PrefService* local_state() { return &local_state_; }
 
-  void SetHighEfficiencyEnabled(bool enabled) {
+  void SetMemorySaverEnabled(bool enabled) {
     local_state()->SetInteger(
         performance_manager::user_tuning::prefs::kMemorySaverModeState,
         static_cast<int>(enabled ? performance_manager::user_tuning::prefs::
@@ -101,7 +101,7 @@
 };
 
 TEST_F(PerformanceManagerMetricsProviderDesktopTest, TestNormalMode) {
-  SetHighEfficiencyEnabled(false);
+  SetMemorySaverEnabled(false);
 
   InitProvider();
   base::HistogramTester tester;
@@ -116,7 +116,7 @@
 
 TEST_F(PerformanceManagerMetricsProviderDesktopTest, TestMixedMode) {
   // Start in normal mode
-  SetHighEfficiencyEnabled(false);
+  SetMemorySaverEnabled(false);
 
   InitProvider();
   {
@@ -136,7 +136,7 @@
     // should result in memory saver being reported as enabled for 50% of the
     // interval
     FastForwardBy(base::Minutes(10));
-    SetHighEfficiencyEnabled(true);
+    SetMemorySaverEnabled(true);
     FastForwardBy(base::Minutes(10));
     provider()->ProvideCurrentSessionData(nullptr);
     ExpectSingleUniqueSample(
@@ -153,7 +153,7 @@
     provider()->ProvideCurrentSessionData(nullptr);
     ExpectSingleUniqueSample(tester,
                              performance_manager::MetricsProviderDesktop::
-                                 EfficiencyMode::kHighEfficiency,
+                                 EfficiencyMode::kMemorySaver,
                              /*battery_saver_percent=*/0,
                              /*memory_saver_percent=*/100);
   }
@@ -174,7 +174,7 @@
 }
 
 TEST_F(PerformanceManagerMetricsProviderDesktopTest, TestBothModes) {
-  SetHighEfficiencyEnabled(true);
+  SetMemorySaverEnabled(true);
   SetBatterySaverEnabled(true);
 
   InitProvider();
@@ -195,7 +195,7 @@
     // Disabling High-Efficiency Mode will cause the next report to be "mixed".
     // Since the time didn't advance, memory saver was off for the entire
     // interval and battery saver was on for it.
-    SetHighEfficiencyEnabled(false);
+    SetMemorySaverEnabled(false);
     provider()->ProvideCurrentSessionData(nullptr);
     ExpectSingleUniqueSample(
         tester,
@@ -219,7 +219,7 @@
     // Re-enabling High-Efficiency Mode will cause the next report to indicate
     // "mixed".
     FastForwardBy(base::Minutes(10));
-    SetHighEfficiencyEnabled(true);
+    SetMemorySaverEnabled(true);
     FastForwardBy(base::Minutes(30));
     provider()->ProvideCurrentSessionData(nullptr);
     ExpectSingleUniqueSample(
@@ -241,7 +241,7 @@
 
 TEST_F(PerformanceManagerMetricsProviderDesktopTest,
        TestCorrectlyLoggedDuringShutdown) {
-  SetHighEfficiencyEnabled(false);
+  SetMemorySaverEnabled(false);
   SetBatterySaverEnabled(true);
 
   InitProvider();
diff --git a/chrome/browser/performance_manager/metrics/page_resource_cpu_monitor.cc b/chrome/browser/performance_manager/metrics/page_resource_cpu_monitor.cc
index d99b4629..b873e04a 100644
--- a/chrome/browser/performance_manager/metrics/page_resource_cpu_monitor.cc
+++ b/chrome/browser/performance_manager/metrics/page_resource_cpu_monitor.cc
@@ -34,7 +34,9 @@
 
 PageResourceCPUMonitor::PageResourceCPUMonitor()
     : cpu_measurement_delegate_factory_(
-          CPUMeasurementDelegate::GetDefaultFactory()) {}
+          CPUMeasurementDelegate::GetDefaultFactory()),
+      cpu_proportion_tracker_(
+          base::BindRepeating(&resource_attribution::ContextIs<PageContext>)) {}
 
 PageResourceCPUMonitor::~PageResourceCPUMonitor() = default;
 
@@ -60,8 +62,10 @@
   last_measurement_time_ = base::TimeTicks::Now();
 
   if (features::kUseResourceAttributionCPUMonitor.Get()) {
-    CHECK(cached_cpu_measurements_.empty());
     cpu_query_ = std::make_unique<resource_attribution::ScopedCPUQuery>();
+    cpu_query_->QueryOnce(base::BindOnce(
+        &PageResourceCPUMonitor::StartResourceAttributionCPUMeasurements,
+        weak_factory_.GetWeakPtr(), last_measurement_time_));
     return;
   }
 
@@ -83,7 +87,7 @@
 
   if (features::kUseResourceAttributionCPUMonitor.Get()) {
     cpu_query_.reset();
-    cached_cpu_measurements_.clear();
+    cpu_proportion_tracker_.Stop();
   } else {
     cpu_measurement_map_.clear();
     graph->RemoveProcessNodeObserver(this);
@@ -100,8 +104,7 @@
   if (features::kUseResourceAttributionCPUMonitor.Get()) {
     cpu_query_->QueryOnce(base::BindOnce(
         &PageResourceCPUMonitor::UpdateResourceAttributionCPUMeasurements,
-        weak_factory_.GetWeakPtr(), std::move(callback),
-        now - last_measurement_time_));
+        weak_factory_.GetWeakPtr(), std::move(callback), now));
   } else {
     CPUUsageMap cpu_usage_map;
     for (auto& [process_node, cpu_measurement] : cpu_measurement_map_) {
@@ -190,109 +193,29 @@
   CHECK(was_inserted);
 }
 
-void PageResourceCPUMonitor::UpdateResourceAttributionCPUMeasurements(
-    base::OnceCallback<void(const CPUUsageMap&)> callback,
-    base::TimeDelta measurement_interval,
+void PageResourceCPUMonitor::StartResourceAttributionCPUMeasurements(
+    base::TimeTicks measurement_interval_start,
     const resource_attribution::QueryResultMap& results) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   CHECK(features::kUseResourceAttributionCPUMonitor.Get());
-  if (measurement_interval.is_zero()) {
-    // No time passed to measure. Ignore the results to avoid division by zero.
+  CHECK(!cpu_proportion_tracker_.IsTracking());
+  cpu_proportion_tracker_.StartFirstInterval(measurement_interval_start,
+                                             results);
+}
+
+void PageResourceCPUMonitor::UpdateResourceAttributionCPUMeasurements(
+    base::OnceCallback<void(const CPUUsageMap&)> callback,
+    base::TimeTicks measurement_interval_end,
+    const resource_attribution::QueryResultMap& results) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  CHECK(features::kUseResourceAttributionCPUMonitor.Get());
+  if (!cpu_proportion_tracker_.IsTracking()) {
+    // StopMonitoring() was called while waiting for update. Ignore the results.
     std::move(callback).Run({});
     return;
   }
-  CHECK(measurement_interval.is_positive());
-
-  // Swap a new measurement into `cached_cpu_measurements_`, storing the
-  // previous contents in `previous_measurements`.
-  resource_attribution::QueryResultMap previous_measurements =
-      std::exchange(cached_cpu_measurements_, results);
-
-  CPUUsageMap cpu_usage_map;
-  for (const auto& [context, query_result] : cached_cpu_measurements_) {
-    using CPUTimeResult = resource_attribution::CPUTimeResult;
-    if (!resource_attribution::ContextIs<PageContext>(context)) {
-      continue;
-    }
-    const auto& result =
-        resource_attribution::AsResult<CPUTimeResult>(query_result).value();
-
-    // Let time A be the last time UpdateCPUMeasurements() was called (with the
-    // results saved in `previous_measurements`), or the time when
-    // StartMonitoring() was called if this is the first one
-    // (`previous_measurements` will be empty).
-    //
-    // Let time B be current time. (`measurement_interval` is A..B.)
-    //
-    // There are 4 cases:
-    //
-    // 1. The context was created at time C, between A and B. (It will not be
-    // found in `previous_measurements`).
-    //
-    // This snapshot should include 0% CPU for time A..C, and the measured % of
-    // CPU for time C..B.
-    //
-    // A    C         B
-    // |----+---------|
-    // | 0% |   X%    |
-    //
-    // CPU(C..B) is `result.cumulative_cpu`.
-    // `result.start_time` is C.
-    // `result.metadata.measurement_time` is B.
-    //
-    // 2. The context existed for the entire duration A..B.
-    //
-    // This snapshot should include the measured % of CPU for the whole time
-    // A..B.
-    //
-    // A              B
-    // |--------------|
-    // |      X%      |
-    //
-    // CPU(A..B) is `result.cumulative_cpu -
-    // previous_measurements[context].cumulative_cpu`.
-    // `result.start_time` <= A.
-    // `result.metadata.measurement_time` is B.
-    //
-    // 3. Context created before time A, exited at time D, between A and B.
-    //
-    // The snapshot should include the measured % of CPU for time A..D, and 0%
-    // CPU for time D..B.
-    //
-    // A         D    B
-    // |---------+----|
-    // |    X%   | 0% |
-    //
-    // CPU(A..D) is `result.cumulative_cpu -
-    // previous_measurements[context].cumulative_cpu`.
-    // `result.start_time` <= A.
-    // `result.metadata.measurement_time` is D.
-    //
-    // 4. Context created at time C and exited at time D, both between A and B.
-    // (context is not found in `previous_measurements`.
-    // `result.cumulative_cpu` ends at time D, which is
-    // `result.metadata.measurement_time`.)
-    //
-    // The snapshot should include the measured % of CPU for time C..D, and 0%
-    // CPU for the rest.
-    //
-    // A    C    D    B
-    // |----+----+----|
-    // | 0% | X% | 0% |
-    //
-    // CPU(C..D) is `result.cumulative_cpu`.
-    // `result.start_time` is C.
-    // `result.metadata.measurement_time` is D.
-    base::TimeDelta current_cpu = result.cumulative_cpu;
-    const auto it = previous_measurements.find(context);
-    if (it != previous_measurements.end()) {
-      const auto& previous_result =
-          resource_attribution::AsResult<CPUTimeResult>(it->second).value();
-      current_cpu -= previous_result.cumulative_cpu;
-    }
-    CHECK(!current_cpu.is_negative());
-    cpu_usage_map.emplace(context, current_cpu / measurement_interval);
-  }
+  CPUUsageMap cpu_usage_map = cpu_proportion_tracker_.StartNextInterval(
+      measurement_interval_end, results);
   std::move(callback).Run(std::move(cpu_usage_map));
 }
 
diff --git a/chrome/browser/performance_manager/metrics/page_resource_cpu_monitor.h b/chrome/browser/performance_manager/metrics/page_resource_cpu_monitor.h
index 320190a..e8aa7b1 100644
--- a/chrome/browser/performance_manager/metrics/page_resource_cpu_monitor.h
+++ b/chrome/browser/performance_manager/metrics/page_resource_cpu_monitor.h
@@ -15,6 +15,7 @@
 #include "base/time/time.h"
 #include "components/performance_manager/public/graph/process_node.h"
 #include "components/performance_manager/public/resource_attribution/cpu_measurement_delegate.h"
+#include "components/performance_manager/public/resource_attribution/cpu_proportion_tracker.h"
 #include "components/performance_manager/public/resource_attribution/query_results.h"
 #include "components/performance_manager/public/resource_attribution/resource_contexts.h"
 #include "components/performance_manager/public/resource_attribution/scoped_cpu_query.h"
@@ -42,11 +43,10 @@
   // ProcessMetrics::GetPlatformIndependentCPUUsage().
   //
   // If the kUseResourceAttributionCPUMonitor feature parameter is enabled, the
-  // map is keyed by PageNode instead since `cpu_measurement_monitor_` returns
-  // page estimates. In production the FrameNode and WorkerNode values are only
-  // ever used as inputs to EstimatePageCPUUsage() to get page estimates, so
-  // it's more efficient to only store the final page estimates when they're
-  // available.
+  // map is keyed by PageNode instead since `cpu_query_` returns page estimates.
+  // In production the FrameNode and WorkerNode values are only ever used as
+  // inputs to EstimatePageCPUUsage() to get page estimates, so it's more
+  // efficient to only store the final page estimates when they're available.
   using CPUUsageMap = std::map<resource_attribution::ResourceContext, double>;
 
   PageResourceCPUMonitor();
@@ -126,12 +126,19 @@
   // `cpu_measurement_map_`.
   void MonitorCPUUsage(const ProcessNode* process_node);
 
-  // Uses results from `cpu_measurement_monitor_` to update CPU measurements.
-  // Called from UpdateCPUMeasurements() if the
+  // Uses results from `cpu_query_` to establish a baseline for the CPU
+  // measurements. Called from StartMonitoring() if the
   // kUseResourceAttributionCPUMonitor feature parameter is enabled.
+  void StartResourceAttributionCPUMeasurements(
+      base::TimeTicks measurement_interval_start,
+      const resource_attribution::QueryResultMap& results);
+
+  // Uses results from `cpu_query_` to update CPU measurements. Called from
+  // UpdateCPUMeasurements() if the kUseResourceAttributionCPUMonitor feature
+  // parameter is enabled.
   void UpdateResourceAttributionCPUMeasurements(
       base::OnceCallback<void(const CPUUsageMap&)> callback,
-      base::TimeDelta measurement_interval,
+      base::TimeTicks measurement_interval_end,
       const resource_attribution::QueryResultMap& results);
 
   SEQUENCE_CHECKER(sequence_checker_);
@@ -158,7 +165,7 @@
   // If the kUseResourceAttributionCPUMonitor feature parameter is enabled, this
   // will cache the measurements of each page when UpdateCPUMeasurements is
   // called. Otherwise it's unused.
-  resource_attribution::QueryResultMap cached_cpu_measurements_
+  resource_attribution::CPUProportionTracker cpu_proportion_tracker_
       GUARDED_BY_CONTEXT(sequence_checker_);
 
   base::WeakPtrFactory<PageResourceCPUMonitor> weak_factory_{this};
diff --git a/chrome/browser/performance_manager/metrics/page_resource_monitor.cc b/chrome/browser/performance_manager/metrics/page_resource_monitor.cc
index f3c350a..2d13062 100644
--- a/chrome/browser/performance_manager/metrics/page_resource_monitor.cc
+++ b/chrome/browser/performance_manager/metrics/page_resource_monitor.cc
@@ -296,12 +296,12 @@
         .SetTabId(curr_info->tab_id);
 
 #if !BUILDFLAG(IS_ANDROID)
-    bool high_efficiency_mode_active =
+    bool memory_saver_mode_active =
         (policies::MemorySaverModePolicy::GetInstance() &&
          policies::MemorySaverModePolicy::GetInstance()
-             ->IsHighEfficiencyDiscardingEnabled());
+             ->IsMemorySaverDiscardingEnabled());
 
-    builder.SetHighEfficiencyMode(high_efficiency_mode_active)
+    builder.SetHighEfficiencyMode(memory_saver_mode_active)
         .SetBatterySaverMode(battery_saver_enabled_);
 #endif  // !BUILDFLAG(IS_ANDROID)
 
diff --git a/chrome/browser/performance_manager/metrics/page_resource_monitor_unittest.cc b/chrome/browser/performance_manager/metrics/page_resource_monitor_unittest.cc
index 0deb9d664..1c21b96 100644
--- a/chrome/browser/performance_manager/metrics/page_resource_monitor_unittest.cc
+++ b/chrome/browser/performance_manager/metrics/page_resource_monitor_unittest.cc
@@ -489,7 +489,7 @@
 }
 
 #if !BUILDFLAG(IS_ANDROID)
-TEST_F(PageResourceMonitorUnitTest, TestHighEfficiencyMode) {
+TEST_F(PageResourceMonitorUnitTest, TestMemorySaverMode) {
   MockSinglePageInSingleProcessGraph mock_graph(graph());
   ukm::SourceId mock_source_id = ukm::NoURLSourceId();
   mock_graph.page->SetType(performance_manager::PageType::kTab);
@@ -849,10 +849,12 @@
   mock_graph.other_page->SetType(performance_manager::PageType::kTab);
   mock_graph.other_page->SetIsVisible(false);
 
-  // Set CPU usage to 0, so only the .Baseline metrics should be logged.
-  cpu_delegate_factory_.GetDelegate(mock_graph.process.get()).SetCPUUsage(0.0);
+  // Set CPU usage to near-0, so only the .Baseline metrics should be logged.
+  // 0 is used as an error value by base::ProcessMetrics so it will cause no
+  // results at all for the process to be returned.
+  cpu_delegate_factory_.GetDelegate(mock_graph.process.get()).SetCPUUsage(0.01);
   cpu_delegate_factory_.GetDelegate(mock_graph.other_process.get())
-      .SetCPUUsage(0.0);
+      .SetCPUUsage(0.01);
 
   {
     PatternedHistogramTester histograms;
diff --git a/chrome/browser/performance_manager/policies/memory_saver_mode_policy.cc b/chrome/browser/performance_manager/policies/memory_saver_mode_policy.cc
index d508f16..7b158e8 100644
--- a/chrome/browser/performance_manager/policies/memory_saver_mode_policy.cc
+++ b/chrome/browser/performance_manager/policies/memory_saver_mode_policy.cc
@@ -124,7 +124,7 @@
   }
 }
 
-bool MemorySaverModePolicy::IsHighEfficiencyDiscardingEnabled() const {
+bool MemorySaverModePolicy::IsMemorySaverDiscardingEnabled() const {
   return high_efficiency_mode_enabled_;
 }
 
@@ -142,7 +142,7 @@
 void MemorySaverModePolicy::StartDiscardTimerIfEnabled(
     const TabPageDecorator::TabHandle* tab_handle,
     base::TimeDelta time_before_discard) {
-  if (IsHighEfficiencyDiscardingEnabled()) {
+  if (IsMemorySaverDiscardingEnabled()) {
     TabRevisitTracker* revisit_tracker =
         graph_->GetRegisteredObjectAs<TabRevisitTracker>();
     CHECK(revisit_tracker);
@@ -188,7 +188,7 @@
 
   // Turning off Memory Saver Mode would delete the timer, so it's not
   // possible to get here and for Memory Saver Mode to be off.
-  DCHECK(IsHighEfficiencyDiscardingEnabled());
+  DCHECK(IsMemorySaverDiscardingEnabled());
 
   // If the time elapsed according to `LiveTicks` is shorter than
   // `requested_time_before_discard`, it means that the device was in a
diff --git a/chrome/browser/performance_manager/policies/memory_saver_mode_policy.h b/chrome/browser/performance_manager/policies/memory_saver_mode_policy.h
index 32ddfe7..75dd4759 100644
--- a/chrome/browser/performance_manager/policies/memory_saver_mode_policy.h
+++ b/chrome/browser/performance_manager/policies/memory_saver_mode_policy.h
@@ -52,7 +52,7 @@
 
   // Returns true if Memory Saver mode is enabled, false otherwise. Useful to
   // get the state of the mode from the Performance Manager sequence.
-  bool IsHighEfficiencyDiscardingEnabled() const;
+  bool IsMemorySaverDiscardingEnabled() const;
 
  private:
   void StartAllDiscardTimers();
diff --git a/chrome/browser/performance_manager/policies/memory_saver_mode_policy_unittest.cc b/chrome/browser/performance_manager/policies/memory_saver_mode_policy_unittest.cc
index 43342d1..4341415 100644
--- a/chrome/browser/performance_manager/policies/memory_saver_mode_policy_unittest.cc
+++ b/chrome/browser/performance_manager/policies/memory_saver_mode_policy_unittest.cc
@@ -106,7 +106,7 @@
   raw_ptr<TestTabRevisitTracker> tab_revisit_tracker_;
 };
 
-TEST_F(MemorySaverModeTest, NoDiscardIfHighEfficiencyOff) {
+TEST_F(MemorySaverModeTest, NoDiscardIfMemorySaverOff) {
   page_node()->SetType(PageType::kTab);
   page_node()->SetIsVisible(true);
   page_node()->SetIsVisible(false);
diff --git a/chrome/browser/performance_manager/public/user_tuning/memory_saver_policy_handler.h b/chrome/browser/performance_manager/public/user_tuning/memory_saver_policy_handler.h
index 300283cc..8a1d925 100644
--- a/chrome/browser/performance_manager/public/user_tuning/memory_saver_policy_handler.h
+++ b/chrome/browser/performance_manager/public/user_tuning/memory_saver_policy_handler.h
@@ -9,8 +9,8 @@
 
 namespace performance_manager {
 
-// A policy handler that maps the boolean HighEfficiencyModeEnabled policy to
-// the enum kMemorySaverModeState pref. This is needed because HighEfficiency
+// A policy handler that maps the boolean MemorySaverModeEnabled policy to
+// the enum kMemorySaverModeState pref. This is needed because MemorySaver
 // was controlled by a boolean pref when the policy was written, but it's now
 // controlled by an integer pref. This policy will eventually be deprecated and
 // replaced by an integer policy.
diff --git a/chrome/browser/permissions/contextual_notification_permission_ui_selector.cc b/chrome/browser/permissions/contextual_notification_permission_ui_selector.cc
index 8c0407e8..202b88f 100644
--- a/chrome/browser/permissions/contextual_notification_permission_ui_selector.cc
+++ b/chrome/browser/permissions/contextual_notification_permission_ui_selector.cc
@@ -41,12 +41,6 @@
           NotificationUserExperienceQuality_ARRAYSIZE);
 }
 
-// Records a histogram sample for the |warning_only| bit.
-void RecordWarningOnlyState(bool value) {
-  base::UmaHistogramBoolean("Permissions.CrowdDeny.PreloadData.WarningOnly",
-                            value);
-}
-
 // Attempts to decide which UI to use based on preloaded site reputation data,
 // or returns absl::nullopt if not possible. |site_reputation| can be nullptr.
 absl::optional<Decision> GetDecisionBasedOnSiteReputation(
@@ -60,7 +54,6 @@
 
   RecordNotificationUserExperienceQuality(
       site_reputation->notification_ux_quality());
-  RecordWarningOnlyState(site_reputation->warning_only());
 
   switch (site_reputation->notification_ux_quality()) {
     case CrowdDenyPreloadData::SiteReputation::ACCEPTABLE: {
diff --git a/chrome/browser/printing/system_access_process_print_browsertest.cc b/chrome/browser/printing/system_access_process_print_browsertest.cc
index 756353d0..bc05657 100644
--- a/chrome/browser/printing/system_access_process_print_browsertest.cc
+++ b/chrome/browser/printing/system_access_process_print_browsertest.cc
@@ -3247,14 +3247,8 @@
 
 #if !BUILDFLAG(IS_CHROMEOS)
 
-// TODO(crbug.com/1496991): Timeout on Mac
-#if BUILDFLAG(IS_MAC)
-#define MAYBE_PrintWithPreviewBeforeLoaded DISABLED_PrintWithPreviewBeforeLoaded
-#else
-#define MAYBE_PrintWithPreviewBeforeLoaded PrintWithPreviewBeforeLoaded
-#endif
 IN_PROC_BROWSER_TEST_P(ContentAnalysisAfterPrintPreviewBrowserTest,
-                       MAYBE_PrintWithPreviewBeforeLoaded) {
+                       PrintWithPreviewBeforeLoaded) {
   AddPrinter("printer_name");
 
   ASSERT_TRUE(embedded_test_server()->Started());
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java
index 8f627de0..b6d5bba4c 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudController.java
@@ -108,6 +108,8 @@
         private final Tab mTab;
         // Paragraph index to resume from.
         private final int mParagraphIndex;
+        // Optional - position within the paragraph to resume from.
+        private final long mOffsetNanos;
         // True if audio should start playing immediately when this state is restored.
         private final boolean mPlaying;
 
@@ -118,13 +120,33 @@
          * @param data Current PlaybackData which may be null if playback hasn't started yet.
          */
         RestoreState(Tab tab, @Nullable PlaybackData data) {
+            this(tab, data, /* useOffsetInParagraph= */ true, /* shouldPlayOverride= */ null);
+        }
+
+        /**
+         * Constructor.
+         *
+         * @param tab Tab to play.
+         * @param data Current PlaybackData which may be null if playback hasn't started yet.
+         */
+        RestoreState(
+                Tab tab,
+                @Nullable PlaybackData data,
+                boolean useOffsetInParagraph,
+                @Nullable Boolean shouldPlayOverride) {
             mTab = tab;
             if (data == null) {
                 mParagraphIndex = 0;
-                mPlaying = true;
+                mOffsetNanos = 0L;
             } else {
                 mParagraphIndex = data.paragraphIndex();
-                mPlaying = data.state() != PAUSED && data.state() != STOPPED;
+                mOffsetNanos = data.positionInParagraphNanos();
+            }
+
+            if (shouldPlayOverride != null) {
+                mPlaying = shouldPlayOverride;
+            } else {
+                mPlaying = data == null ? true : data.state() != PAUSED && data.state() != STOPPED;
             }
         }
 
@@ -140,9 +162,9 @@
                                     mPlayerCoordinator.playbackReady(playback, PAUSED);
                                 }
 
-                                if (mParagraphIndex != 0) {
+                                if (mParagraphIndex != 0 || mOffsetNanos != 0) {
                                     playback.seekToParagraph(
-                                            mParagraphIndex, /* offsetNanos= */ 0L);
+                                            mParagraphIndex, /* offsetNanos= */ mOffsetNanos);
                                 }
                             },
                             exception -> {
@@ -157,6 +179,8 @@
     // State of playback that was interrupted by a voice preview and should be
     // restored when closing the voice menu.
     @Nullable private RestoreState mStateToRestoreOnVoiceMenuClose;
+    // State of playback that was interrupted by backgrounding Chrome.
+    @Nullable private RestoreState mStateToRestoreOnBringingToForeground;
 
     // Whether or not to highlight the page. Change will only have effect if
     // isHighlightingSupported() returns true.
@@ -478,6 +502,7 @@
         mHighlightingEnabled.removeObserver(ReadAloudController.this::onHighlightingEnabledChanged);
         ApplicationStatus.unregisterApplicationStateListener(this);
         resetCurrentPlayback();
+        mStateToRestoreOnBringingToForeground = null;
     }
 
     private void maybeSetUpHighlighter(Playback.Metadata metadata) {
@@ -781,7 +806,19 @@
         if (newState == ApplicationState.HAS_STOPPED_ACTIVITIES
                 && DeviceConditions.isCurrentlyScreenOnAndUnlocked(
                         mActivity.getApplicationContext())) {
-            maybeStopPlayback(/* tab= */ null);
+            if (mCurrentlyPlayingTab != null) {
+                mStateToRestoreOnBringingToForeground =
+                        new RestoreState(
+                                mCurrentlyPlayingTab,
+                                mCurrentPlaybackData,
+                                /* useOffsetInParagraph= */ true,
+                                /* shouldPlayOverride= */ false);
+            }
+            resetCurrentPlayback();
+        } else if (newState == ApplicationState.HAS_RUNNING_ACTIVITIES
+                && mStateToRestoreOnBringingToForeground != null) {
+            mStateToRestoreOnBringingToForeground.restore();
+            mStateToRestoreOnBringingToForeground = null;
         }
     }
 
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudControllerUnitTest.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudControllerUnitTest.java
index fa634f01..00d2f36 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudControllerUnitTest.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/ReadAloudControllerUnitTest.java
@@ -37,6 +37,7 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowLooper;
 
+import org.chromium.base.ApplicationState;
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.HistogramWatcher;
@@ -1115,6 +1116,43 @@
         assertFalse(mController.isReadable(mTab));
     }
 
+    @Test
+    public void testPlaybackStopsAndStateSavedWhenAppBackgrounded() {
+        // Play tab.
+        mFakeTranslateBridge.setCurrentLanguage("en");
+        mTab.setGurlOverrideForTesting(new GURL("https://en.wikipedia.org/wiki/Google"));
+        mController.playTab(mTab);
+        verify(mPlaybackHooks).createPlayback(any(), mPlaybackCallbackCaptor.capture());
+        onPlaybackSuccess(mPlayback);
+        verify(mPlayback, times(1)).play();
+        var data = Mockito.mock(PlaybackData.class);
+        // set progress
+        doReturn(2).when(data).paragraphIndex();
+        doReturn(1000000L).when(data).positionInParagraphNanos();
+        mController.onPlaybackDataChanged(data);
+
+        // App is backgrounded. Make sure playback stops.
+        mController.onApplicationStateChange(ApplicationState.HAS_STOPPED_ACTIVITIES);
+        verify(mPlayback).release();
+        reset(mPlayback);
+
+        // App goes back in foreground. Restore progress.
+        mController.onApplicationStateChange(ApplicationState.HAS_RUNNING_ACTIVITIES);
+        verify(mPlaybackHooks, times(2)).createPlayback(any(), mPlaybackCallbackCaptor.capture());
+        onPlaybackSuccess(mPlayback);
+        verify(mPlayback).seekToParagraph(2, 1000000L);
+        verify(mPlayback, never()).play();
+
+        // once saved state is restored, it's cleared and no further interactions with playback
+        // should happen.
+        reset(mPlayback);
+        reset(mPlaybackHooks);
+        mController.onApplicationStateChange(ApplicationState.HAS_PAUSED_ACTIVITIES);
+        mController.onApplicationStateChange(ApplicationState.HAS_RUNNING_ACTIVITIES);
+        verify(mPlaybackHooks, never()).createPlayback(any(), mPlaybackCallbackCaptor.capture());
+        verify(mPlayback, never()).release();
+    }
+
     private void onPlaybackSuccess(Playback playback) {
         mPlaybackCallbackCaptor.getValue().onSuccess(playback);
         resolvePromises();
diff --git a/chrome/browser/resources/ash/settings/crostini_page/crostini_extra_containers.ts b/chrome/browser/resources/ash/settings/crostini_page/crostini_extra_containers.ts
index ce0cd542..77b39bb 100644
--- a/chrome/browser/resources/ash/settings/crostini_page/crostini_extra_containers.ts
+++ b/chrome/browser/resources/ash/settings/crostini_page/crostini_extra_containers.ts
@@ -25,6 +25,7 @@
 import {hexColorToSkColor} from 'chrome://resources/js/color_utils.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
+import {PrefsState} from '../common/types.js';
 import {ContainerInfo, GuestId, ShareableDevices, VM_DEVICE_MICROPHONE} from '../guest_os/guest_os_browser_proxy.js';
 import {equalContainerId} from '../guest_os/guest_os_container_select.js';
 
@@ -63,6 +64,11 @@
 
   static get properties() {
     return {
+      prefs: {
+        type: Object,
+        notify: true,
+      },
+
       showCreateContainerDialog_: {
         type: Boolean,
         value: false,
@@ -118,6 +124,7 @@
     };
   }
 
+  prefs: PrefsState;
   private allContainers_: CrostiniContainerInfo[];
   private allSharedVmDevices_: SharedVmDevices[];
   private allVms_: string[];
diff --git a/chrome/browser/resources/ash/settings/device_page/display.html b/chrome/browser/resources/ash/settings/device_page/display.html
index 9d989a7..6b879454 100644
--- a/chrome/browser/resources/ash/settings/device_page/display.html
+++ b/chrome/browser/resources/ash/settings/device_page/display.html
@@ -49,7 +49,8 @@
 <!-- Night Light Settings -->
 <template is="dom-if"
     if="[[isRevampWayfindingEnabled_]]" restamp>
-  <settings-display-night-light prefs="{{prefs}}">
+  <settings-display-night-light prefs="{{prefs}}"
+    is-internal-display="[[selectedDisplay.isInternal]]">
   </settings-display-night-light>
   <div class="hr"></div>
 </template>
@@ -318,6 +319,7 @@
 <template is="dom-if"
     if="[[!isRevampWayfindingEnabled_]]" restamp>
   <div class="hr"></div>
-  <settings-display-night-light prefs="{{prefs}}">
+  <settings-display-night-light prefs="{{prefs}}"
+    is-internal-display="[[selectedDisplay.isInternal]]">
   </settings-display-night-light>
 </template>
diff --git a/chrome/browser/resources/ash/settings/device_page/display.ts b/chrome/browser/resources/ash/settings/device_page/display.ts
index 81a2166..e874731 100644
--- a/chrome/browser/resources/ash/settings/device_page/display.ts
+++ b/chrome/browser/resources/ash/settings/device_page/display.ts
@@ -1194,8 +1194,10 @@
         DisplaySettingsType.kRefreshRate :
         DisplaySettingsType.kResolution;
     this.displaySettingsProvider.recordChangingDisplaySettings(
-        displaySettingsType,
-        {isInternalDisplay: this.selectedDisplay.isInternal});
+        displaySettingsType, {
+          isInternalDisplay: this.selectedDisplay.isInternal,
+          displayId: BigInt(this.selectedDisplay.id),
+        });
   }
 
   /**
@@ -1216,8 +1218,10 @@
         .setDisplayProperties(this.selectedDisplay.id, properties)
         .then(() => this.setPropertiesCallback_());
     this.displaySettingsProvider.recordChangingDisplaySettings(
-        DisplaySettingsType.kScaling,
-        {isInternalDisplay: this.selectedDisplay.isInternal});
+        DisplaySettingsType.kScaling, {
+          isInternalDisplay: this.selectedDisplay.isInternal,
+          displayId: BigInt(this.selectedDisplay.id),
+        });
   }
 
   /**
diff --git a/chrome/browser/resources/ash/settings/device_page/display_night_light.ts b/chrome/browser/resources/ash/settings/device_page/display_night_light.ts
index ebd52c6e..828cd1e 100644
--- a/chrome/browser/resources/ash/settings/device_page/display_night_light.ts
+++ b/chrome/browser/resources/ash/settings/device_page/display_night_light.ts
@@ -24,10 +24,12 @@
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {DeepLinkingMixin} from '../common/deep_linking_mixin.js';
+import {DisplaySettingsProviderInterface, DisplaySettingsType} from '../mojom-webui/display_settings_provider.mojom-webui.js';
 import {Setting} from '../mojom-webui/setting.mojom-webui.js';
 import {GeolocationAccessLevel} from '../os_privacy_page/privacy_hub_geolocation_subpage.js';
 
 import {getTemplate} from './display_night_light.html.js';
+import {getDisplaySettingsProvider} from './display_settings_mojo_interface_provider.js';
 
 /**
  * The types of Night Light automatic schedule. The values of the enum values
@@ -112,6 +114,18 @@
         type: Boolean,
         value: false,
       },
+
+      isInternalDisplay: Boolean,
+
+      /**
+       * Current status of night light setting.
+       */
+      currentNightLightStatus: Boolean,
+
+      /**
+       * Current selected night light schedule type.
+       */
+      currentScheduleType: NightLightScheduleType,
     };
   }
 
@@ -122,11 +136,17 @@
     ];
   }
 
+  isInternalDisplay: boolean;
+  private displaySettingsProvider: DisplaySettingsProviderInterface =
+      getDisplaySettingsProvider();
   private nightLightScheduleSubLabel_: string;
   private scheduleTypesList_: ScheduleType[];
   private shouldOpenCustomScheduleCollapse_: boolean;
   private shouldShowGeolocationDialog_: boolean;
   private shouldShowGeolocationWarningText_: boolean;
+  private currentNightLightStatus: boolean;
+  private currentScheduleType: NightLightScheduleType;
+
   /**
    * Invoked when the status of Night Light or its schedule type are changed,
    * in order to update the schedule settings, such as whether to show the
@@ -137,14 +157,41 @@
     this.shouldOpenCustomScheduleCollapse_ =
         scheduleType === NightLightScheduleType.CUSTOM;
 
+    const nightLightStatus: boolean =
+        this.getPref('ash.night_light.enabled').value;
     if (scheduleType === NightLightScheduleType.SUNSET_TO_SUNRISE) {
-      const nightLightStatus = this.getPref('ash.night_light.enabled').value;
       this.nightLightScheduleSubLabel_ = nightLightStatus ?
           this.i18n('displayNightLightOffAtSunrise') :
           this.i18n('displayNightLightOnAtSunset');
     } else {
       this.nightLightScheduleSubLabel_ = '';
     }
+
+    // Records metrics when schedule type or night light status have changed. Do
+    // not record when the page just loads and the current value is still
+    // undefined.
+    if (this.currentScheduleType !== scheduleType &&
+        this.currentScheduleType !== undefined) {
+      this.recordNightLightSettingsMetrics(
+          DisplaySettingsType.kNightLightSchedule, this.isInternalDisplay);
+    }
+    if (this.currentNightLightStatus !== nightLightStatus &&
+        this.currentNightLightStatus !== undefined) {
+      this.recordNightLightSettingsMetrics(
+          DisplaySettingsType.kNightLight, this.isInternalDisplay);
+    }
+
+    // Updates current schedule type and night light status.
+    this.currentScheduleType = scheduleType;
+    this.currentNightLightStatus = nightLightStatus;
+  }
+
+  // Records metrics when users change the night light settings.
+  private recordNightLightSettingsMetrics(
+      displaySettingsType: DisplaySettingsType,
+      isInternalDisplay: boolean): void {
+    this.displaySettingsProvider.recordChangingDisplaySettings(
+        displaySettingsType, {isInternalDisplay});
   }
 
   private computeShouldShowGeolocationWarningText_(): boolean {
diff --git a/chrome/browser/resources/chromeos/BUILD.gn b/chrome/browser/resources/chromeos/BUILD.gn
index adb59a3..c97beb3 100644
--- a/chrome/browser/resources/chromeos/BUILD.gn
+++ b/chrome/browser/resources/chromeos/BUILD.gn
@@ -85,11 +85,6 @@
 group("closure_compile") {
   deps = [
     ":closure_compile_local",
-    "accessibility/accessibility_common:closure_compile",
-    "accessibility/braille_ime:closure_compile",
-    "accessibility/chromevox:closure_compile",
-    "accessibility/select_to_speak:closure_compile",
-    "accessibility/switch_access:closure_compile",
     "account_manager:closure_compile",
     "account_manager/components:closure_compile",
     "arc_account_picker:closure_compile",
diff --git a/chrome/browser/resources/chromeos/accessibility/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/BUILD.gn
index 088b2783..57b1985f 100644
--- a/chrome/browser/resources/chromeos/accessibility/BUILD.gn
+++ b/chrome/browser/resources/chromeos/accessibility/BUILD.gn
@@ -6,6 +6,7 @@
 import("//build/config/features.gni")
 import("//chrome/common/features.gni")
 import("//chrome/test/base/ash/js2gtest.gni")
+import("//tools/typescript/ts_library.gni")
 import("strings/accessibility_strings.gni")
 import("tools/manifest.gni")
 import("tools/run_jsbundler.gni")
@@ -13,6 +14,9 @@
 assert(is_chromeos_ash)
 
 accessibility_out_dir = "$root_out_dir/resources/chromeos/accessibility/"
+tsc_out_dir = "$target_gen_dir/tsc"
+
+loader_files = [ "switch_access_loader.ts" ]
 
 group("build") {
   deps = [
@@ -44,10 +48,30 @@
   }
 }
 
+ts_library("ts_build") {
+  out_dir = tsc_out_dir
+  definitions = [
+    "definitions/automation.d.ts",
+    "definitions/command_line_private.d.ts",
+    "definitions/extension_types.d.ts",
+    "definitions/extensions.d.ts",
+    "definitions/runtime.d.ts",
+    "definitions/tabs.d.ts",
+    "//tools/typescript/definitions/windows.d.ts",
+  ]
+
+  in_files = loader_files
+  tsconfig_base = "tsconfig.base.json"
+}
+
 run_jsbundler("copied_loader_files") {
   mode = "copy"
+  deps = [ ":ts_build" ]
   dest_dir = accessibility_out_dir
-  sources = [ "switch_access_loader.js" ]
+  sources = []
+  foreach(_ts_file, loader_files) {
+    sources += [ "$tsc_out_dir/" + get_path_info(_ts_file, "name") + ".js" ]
+  }
   rewrite_rules = [ rebase_path(".", root_build_dir) + ":" ]
 }
 
diff --git a/chrome/browser/resources/chromeos/accessibility/PRESUBMIT.py b/chrome/browser/resources/chromeos/accessibility/PRESUBMIT.py
index 66a3417..6fd38c59 100644
--- a/chrome/browser/resources/chromeos/accessibility/PRESUBMIT.py
+++ b/chrome/browser/resources/chromeos/accessibility/PRESUBMIT.py
@@ -4,7 +4,6 @@
 
 import os
 
-
 def _CheckNoJsChanges(input_api, output_api):
   """Enforce that JavaScript files are not changed.
 
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/accessibility_common/BUILD.gn
index 58aada4..dd7a89c 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/BUILD.gn
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/BUILD.gn
@@ -20,8 +20,6 @@
 accessibility_common_dir =
     "$root_out_dir/resources/chromeos/accessibility/accessibility_common"
 tsc_out_dir = "$target_gen_dir/tsc"
-common_tsc_out_dir = "$target_gen_dir/../common/tsc/common"
-accessibility_common_tsc_out_dir = "$tsc_out_dir/accessibility_common"
 
 # TS files to build.
 ts_modules = [
@@ -93,7 +91,7 @@
 }
 
 group("build") {
-  deps = [ ":accessibility_common_copied_files" ]
+  deps = [ ":copied_files" ]
 
   if (include_mediapipe_task_vision_files_for_facegaze) {
     deps += [ ":extract_mediapipe_task_vision_files" ]
@@ -101,13 +99,12 @@
 }
 
 # Instead of setting up copy targets, use a script to copy all files.
-run_jsbundler("accessibility_common_copied_files") {
+run_jsbundler("copied_files") {
   mode = "copy"
   dest_dir = accessibility_common_dir
   deps = [
     ":ts_build",
-    "../common:accessibility_common_copied_files",
-    "../common:ts_build",
+    "../common:copied_files",
   ]
   sources = [
     "background.html",
@@ -123,16 +120,10 @@
     "dictation/parse/speech_parser.js",
     "facegaze/camera_stream.html",
   ]
-
-  foreach(_ts_file, ts_modules) {
-    sources += [ "$accessibility_common_tsc_out_dir/" +
-                 get_path_info(_ts_file, "dir") + "/" +
-                 get_path_info(_ts_file, "name") + ".js" ]
-  }
+  sources += get_target_outputs(":ts_build")
 
   rewrite_rules = [
-    rebase_path(accessibility_common_tsc_out_dir, root_build_dir) + ":",
-    rebase_path(common_tsc_out_dir, root_build_dir) + ":",
+    rebase_path("$tsc_out_dir/accessibility_common", root_build_dir) + ":",
     rebase_path(".", root_build_dir) + ":",
     rebase_path(closure_library_dir, root_build_dir) + ":closure",
   ]
@@ -212,9 +203,6 @@
   defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
 }
 
-group("closure_compile") {
-}
-
 action("pumpkin_test_files") {
   testonly = true
 
diff --git a/chrome/browser/resources/chromeos/accessibility/braille_ime/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/braille_ime/BUILD.gn
index 44cb379..eec419d 100644
--- a/chrome/browser/resources/chromeos/accessibility/braille_ime/BUILD.gn
+++ b/chrome/browser/resources/chromeos/accessibility/braille_ime/BUILD.gn
@@ -3,7 +3,6 @@
 # found in the LICENSE file.
 
 import("//build/config/chromeos/ui_mode.gni")
-import("//third_party/closure_compiler/compile_js.gni")
 import("//tools/typescript/ts_library.gni")
 import("../tools/run_jsbundler.gni")
 
@@ -21,8 +20,8 @@
 
 group("build") {
   deps = [
-    ":braille_ime_copied_files",
     ":braille_ime_manifest",
+    ":copied_files",
   ]
 }
 
@@ -40,7 +39,7 @@
   ]
 }
 
-run_jsbundler("braille_ime_copied_files") {
+run_jsbundler("copied_files") {
   mode = "copy"
   dest_dir = braille_ime_out_dir
   deps = [ ":ts_build" ]
@@ -59,6 +58,3 @@
     rebase_path(".", root_build_dir) + ":",
   ]
 }
-
-group("closure_compile") {
-}
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
index 139441d3..23b2b97 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
@@ -16,7 +16,6 @@
 closure_library_dir =
     "//third_party/chromevox/third_party/closure-library/closure/goog"
 tsc_out_dir = "$target_gen_dir/tsc"
-common_tsc_out_dir = "$target_gen_dir/../common/tsc"
 
 # List of all modules that are included in one or more of the production
 # chromevox scripts.
@@ -24,15 +23,6 @@
 # TS files to compile.
 ts_modules = []
 
-# TS files needed from ../common/.
-common_ts_modules = [
-  "flags.ts",
-  "automation_util.ts",
-  "instance_checker.ts",
-  "tree_walker.ts",
-  "string_util.ts",
-]
-
 # These files all use older Closure provide/require support for dependency management and will be transitioned to ES6 modules (see below).
 chromevox_modules = [
   "background/braille/cursor_dots.js",
@@ -40,8 +30,6 @@
   "third_party/tamachiyomi/ja_phonetic_data.js",
 ]
 
-tsc_common_out_dir = "$target_gen_dir/../common/tsc"
-
 # ES6 modules.
 chromevox_es6_modules = [
   "../common/automation_predicate.js",
@@ -208,7 +196,6 @@
 ts_library("ts_build") {
   root_dir = "../"
   out_dir = tsc_out_dir
-  deps = [ "../common:ts_build" ]
   definitions = []
 
   in_files = []
@@ -223,9 +210,9 @@
 group("build") {
   deps = [
     ":chromevox_background_script",
-    ":chromevox_copied_files",
     ":chromevox_panel_script",
     ":chromevox_phonetic_dictionaries_js",
+    ":copied_files",
     "//third_party/chromevox:chromevox_third_party_resources",
     "//third_party/liblouis",
   ]
@@ -241,10 +228,13 @@
 
 # Instead of setting up one copy target for each subdirectory, use a script
 # to copy all files.
-run_jsbundler("chromevox_copied_files") {
+run_jsbundler("copied_files") {
   mode = "copy"
   dest_dir = chromevox_out_dir
-  deps = [ "../common:ts_build" ]
+  deps = [
+    ":ts_build",
+    "../common:copied_files",
+  ]
   sources = [
     "background/background.html",
     "earcons/chromevox_loaded.ogg",
@@ -272,19 +262,10 @@
     "tutorial/practice_areas/selects.html",
   ]
   sources += chromevox_es6_modules
-
-  foreach(_ts_file, ts_modules) {
-    sources += [ "$tsc_out_dir/chromevox/" + get_path_info(_ts_file, "dir") +
-                 "/" + get_path_info(_ts_file, "name") + ".js" ]
-  }
-  foreach(_ts_file, common_ts_modules) {
-    sources += [ "$common_tsc_out_dir/" + get_path_info(_ts_file, "dir") + "/" +
-                 get_path_info(_ts_file, "name") + ".js" ]
-  }
+  sources += get_target_outputs(":ts_build")
 
   rewrite_rules = [
     rebase_path("$tsc_out_dir/chromevox", root_build_dir) + ":",
-    rebase_path(common_tsc_out_dir, root_build_dir) + ":",
     rebase_path(".", root_build_dir) + ":",
     rebase_path(closure_library_dir, root_build_dir) + ":closure",
   ]
@@ -503,6 +484,3 @@
     defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
   }
 }
-
-group("closure_compile") {
-}
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.js b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.js
index 5a83273..7cd34f8 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.js
@@ -563,7 +563,7 @@
    * @private
    */
   onOptions_() {
-    chrome.runtime.openOptionsPage();
+    chrome.accessibilityPrivate.openSettingsSubpage('textToSpeech/chromeVox');
     this.setMode(PanelMode.COLLAPSED);
   }
 
diff --git a/chrome/browser/resources/chromeos/accessibility/common/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/common/BUILD.gn
index 0298a82..3ba78bd7 100644
--- a/chrome/browser/resources/chromeos/accessibility/common/BUILD.gn
+++ b/chrome/browser/resources/chromeos/accessibility/common/BUILD.gn
@@ -19,7 +19,7 @@
 
 group("build") {
   deps = [
-    ":accessibility_common_copied_files",
+    ":copied_files",
     "tutorial:build",
   ]
 }
@@ -55,7 +55,7 @@
   tsconfig_base = "../tsconfig.base.json"
 }
 
-run_jsbundler("accessibility_common_copied_files") {
+run_jsbundler("copied_files") {
   mode = "copy"
   dest_dir = accessibility_common_out_dir
   deps = [ ":ts_build" ]
@@ -82,11 +82,7 @@
     "testing/accessibility_test_base.js",
     "testing/test_node_generator.js",
   ]
-
-  foreach(_ts_file, ts_modules) {
-    sources += [ "$tsc_out_dir/" + get_path_info(_ts_file, "dir") + "/" +
-                 get_path_info(_ts_file, "name") + ".js" ]
-  }
+  sources += get_target_outputs(":ts_build")
 
   rewrite_rules = [
     rebase_path(tsc_out_dir, root_build_dir) + ":",
diff --git a/chrome/browser/resources/chromeos/accessibility/common/automation_test_support.js b/chrome/browser/resources/chromeos/accessibility/common/automation_test_support.js
index 0c0a589f..19672f05 100644
--- a/chrome/browser/resources/chromeos/accessibility/common/automation_test_support.js
+++ b/chrome/browser/resources/chromeos/accessibility/common/automation_test_support.js
@@ -101,6 +101,21 @@
   }
 
   /**
+   * Does the default action on the node with the given `name` and `role` after
+   * waiting for that node to exist.
+   * @param {string} name
+   * @param {string} role
+   */
+  doDefault(name, role) {
+    const findParams = {role, attributes: {name}};
+    const node = this.desktop_.find(findParams);
+    if (node) {
+      node.doDefault();
+      this.notifyCcTests_('ready');
+    }
+  }
+
+  /**
    * @param {chrome.automation.FindParams} findParams
    * @private
    */
diff --git a/chrome/browser/resources/chromeos/accessibility/enhanced_network_tts/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/enhanced_network_tts/BUILD.gn
index e3cc774..7140604 100644
--- a/chrome/browser/resources/chromeos/accessibility/enhanced_network_tts/BUILD.gn
+++ b/chrome/browser/resources/chromeos/accessibility/enhanced_network_tts/BUILD.gn
@@ -15,7 +15,6 @@
 enhanced_network_tts_dir =
     "$root_out_dir/resources/chromeos/accessibility/enhanced_network_tts"
 tsc_out_dir = "$target_gen_dir/tsc"
-common_tsc_out_dir = "$target_gen_dir/../common/tsc"
 
 # TS files to compile.
 ts_modules = [
@@ -23,9 +22,6 @@
   "enhanced_network_tts.ts",
 ]
 
-# TS files needed from ../common/.
-common_ts_modules = [ "instance_checker.ts" ]
-
 # JS files needed by the TS compiler.
 js_deps = []
 
@@ -56,33 +52,23 @@
 }
 
 group("build") {
-  deps = [ ":enhanced_network_tts_copied_files" ]
+  deps = [ ":copied_files" ]
 }
 
 # Instead of setting up one copy target for each subdirectory, use a script
 # to copy all files.
-run_jsbundler("enhanced_network_tts_copied_files") {
+run_jsbundler("copied_files") {
   mode = "copy"
   deps = [
     ":ts_build",
-    "../common:ts_build",
+    "../common:copied_files",
   ]
   dest_dir = enhanced_network_tts_dir
   sources = [ "background.html" ]
-
-  foreach(_ts_file, ts_modules) {
-    sources += [ "$tsc_out_dir/enhanced_network_tts/" +
-                 get_path_info(_ts_file, "dir") + "/" +
-                 get_path_info(_ts_file, "name") + ".js" ]
-  }
-  foreach(_ts_file, common_ts_modules) {
-    sources += [ "$common_tsc_out_dir/" + get_path_info(_ts_file, "dir") + "/" +
-                 get_path_info(_ts_file, "name") + ".js" ]
-  }
+  sources += get_target_outputs(":ts_build")
 
   rewrite_rules = [
     rebase_path("$tsc_out_dir/enhanced_network_tts", root_build_dir) + ":",
-    rebase_path(common_tsc_out_dir, root_build_dir) + ":",
     rebase_path(".", root_build_dir) + ":",
     rebase_path(closure_library_dir, root_build_dir) + ":closure",
   ]
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/select_to_speak/BUILD.gn
index 840bca6..8ae1486 100644
--- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/BUILD.gn
+++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/BUILD.gn
@@ -16,13 +16,9 @@
 select_to_speak_out_dir =
     "$root_out_dir/resources/chromeos/accessibility/select_to_speak"
 tsc_out_dir = "$target_gen_dir/tsc"
-common_tsc_out_dir = "$target_gen_dir/../common/tsc"
 
 group("build") {
-  deps = [
-    ":select_to_speak_copied_files",
-    ":ts_build",
-  ]
+  deps = [ ":copied_files" ]
 }
 
 # Add typescript files to compile here.
@@ -37,13 +33,6 @@
   "select_to_speak.ts",
 ]
 
-# Add TS files needed from ../common/ here.
-common_ts_modules = [
-  "instance_checker.ts",
-  "automation_util.ts",
-  "tree_walker.ts",
-]
-
 # Root dir must be the parent directory so it can reach common.
 ts_library("ts_build") {
   root_dir = "../"
@@ -76,12 +65,12 @@
 
 # Instead of setting up one copy target for each subdirectory, use a script
 # to copy all files.
-run_jsbundler("select_to_speak_copied_files") {
+run_jsbundler("copied_files") {
   mode = "copy"
   dest_dir = select_to_speak_out_dir
   deps = [
     ":ts_build",
-    "../common:ts_build",
+    "../common:copied_files",
   ]
   sources = [
     "background.html",
@@ -93,20 +82,10 @@
     "sts-icon-48.png",
     "unchecked.png",
   ]
-
-  foreach(_ts_file, ts_modules) {
-    sources +=
-        [ "$tsc_out_dir/select_to_speak/" + get_path_info(_ts_file, "dir") +
-          "/" + get_path_info(_ts_file, "name") + ".js" ]
-  }
-  foreach(_ts_file, common_ts_modules) {
-    sources += [ "$common_tsc_out_dir/" + get_path_info(_ts_file, "dir") + "/" +
-                 get_path_info(_ts_file, "name") + ".js" ]
-  }
+  sources += get_target_outputs(":ts_build")
 
   rewrite_rules = [
     rebase_path("$tsc_out_dir/select_to_speak", root_build_dir) + ":",
-    rebase_path(common_tsc_out_dir, root_build_dir) + ":",
     rebase_path(".", root_build_dir) + ":",
     rebase_path(closure_library_dir, root_build_dir) + ":closure",
   ]
@@ -175,6 +154,3 @@
   ]
   defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
 }
-
-group("closure_compile") {
-}
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/switch_access/BUILD.gn
index 6549718..91e12825 100644
--- a/chrome/browser/resources/chromeos/accessibility/switch_access/BUILD.gn
+++ b/chrome/browser/resources/chromeos/accessibility/switch_access/BUILD.gn
@@ -16,14 +16,10 @@
 switch_access_dir =
     "$root_out_dir/resources/chromeos/accessibility/switch_access"
 tsc_out_dir = "$target_gen_dir/tsc"
-common_tsc_out_dir = "$target_gen_dir/../common/tsc"
 
 # TS files to compile.
 ts_modules = []
 
-# TS files needed from ../common/.
-common_ts_modules = []
-
 # JS files needed to compile TS.
 js_deps = []
 
@@ -31,7 +27,6 @@
 ts_library("ts_build") {
   root_dir = "../"
   out_dir = tsc_out_dir
-  deps = [ "../common:ts_build" ]
   definitions = []
 
   in_files = []
@@ -46,14 +41,18 @@
 }
 
 group("build") {
-  deps = [ ":switch_access_copied_files" ]
+  deps = [ ":copied_files" ]
 }
 
 # Instead of setting up one copy target for each subdirectory, use a script
 # to copy all files.
-run_jsbundler("switch_access_copied_files") {
+run_jsbundler("copied_files") {
   mode = "copy"
   dest_dir = switch_access_dir
+  deps = [
+    ":ts_build",
+    "../common:copied_files",
+  ]
   sources = [
     "action_manager.js",
     "auto_scan_manager.js",
@@ -112,20 +111,10 @@
     "switch_access_predicate.js",
     "text_navigation_manager.js",
   ]
-
-  foreach(_ts_file, ts_modules) {
-    sources +=
-        [ "$tsc_out_dir/switch_access/" + get_path_info(_ts_file, "dir") + "/" +
-          get_path_info(_ts_file, "name") + ".js" ]
-  }
-  foreach(_ts_file, common_ts_modules) {
-    sources += [ "$common_tsc_out_dir/" + get_path_info(_ts_file, "dir") + "/" +
-                 get_path_info(_ts_file, "name") + ".js" ]
-  }
+  sources += get_target_outputs(":ts_build")
 
   rewrite_rules = [
     rebase_path("$tsc_out_dir/switch_access", root_build_dir) + ":",
-    rebase_path(common_tsc_out_dir, root_build_dir) + ":",
     rebase_path(".", root_build_dir) + ":",
     rebase_path(closure_library_dir, root_build_dir) + ":closure",
   ]
@@ -183,6 +172,3 @@
   ]
   defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
 }
-
-group("closure_compile") {
-}
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access_loader.js b/chrome/browser/resources/chromeos/accessibility/switch_access_loader.ts
similarity index 95%
rename from chrome/browser/resources/chromeos/accessibility/switch_access_loader.js
rename to chrome/browser/resources/chromeos/accessibility/switch_access_loader.ts
index ecfcc956..7d92f7a2 100644
--- a/chrome/browser/resources/chromeos/accessibility/switch_access_loader.js
+++ b/chrome/browser/resources/chromeos/accessibility/switch_access_loader.ts
@@ -14,7 +14,7 @@
 
 InstanceChecker.closeExtraInstances();
 
-async function initAll() {
+async function initAll(): Promise<void> {
   await Flags.init();
   const desktop = await AsyncUtil.getDesktop();
   await SwitchAccess.init(desktop);
diff --git a/chrome/browser/resources/compose/textarea.html b/chrome/browser/resources/compose/textarea.html
index dbbe1a8..121b443d 100644
--- a/chrome/browser/resources/compose/textarea.html
+++ b/chrome/browser/resources/compose/textarea.html
@@ -150,13 +150,14 @@
       value="{{value::input}}"
       rows="4"
       required
-      autofocus>
+      autofocus
+      aria-invalid="[[invalidInput_]]"
+      aria-errormessage="error">
   </textarea>
-  <div class="error" id="tooShortError" hidden$="[[!tooShort_]]">
-    $i18n{errorTooShort}
-  </div>
-  <div class="error" id="tooLongError" hidden$="[[!tooLong_]]">
-    $i18n{errorTooLong}
+  <div id="error" class="error" role="region" aria-live="assertive"
+      hidden$="[[!invalidInput_]]">
+    <div id="tooShortError" hidden$="[[!tooShort_]]">$i18n{errorTooShort}</div>
+    <div id="tooLongError" hidden$="[[!tooLong_]]">$i18n{errorTooLong}</div>
   </div>
 </div>
 
diff --git a/chrome/browser/resources/nearby_internals/BUILD.gn b/chrome/browser/resources/nearby_internals/BUILD.gn
index f002f7d9..b26624d1e 100644
--- a/chrome/browser/resources/nearby_internals/BUILD.gn
+++ b/chrome/browser/resources/nearby_internals/BUILD.gn
@@ -75,7 +75,7 @@
                "nearby_http_browser_proxy.js",
                "cross_device_logs_browser_proxy.js",
                "nearby_presence_browser_proxy.js",
-               "chime_browser_proxy.js",
+               "push_notification_browser_proxy.js",
                "nearby_prefs_browser_proxy.js",
                "nearby_ui_trigger_browser_proxy.js",
                "types.js",
@@ -113,7 +113,6 @@
 js_type_check("closure_compile") {
   is_polymer3 = true
   deps = [
-    ":chime_browser_proxy",
     ":contact_object",
     ":contact_tab",
     ":cross_device_internals",
@@ -130,6 +129,7 @@
     ":nearby_presence_browser_proxy",
     ":nearby_ui_trigger_browser_proxy",
     ":np_list_object",
+    ":push_notification_browser_proxy",
     ":types",
     ":ui_trigger_list_object",
     ":ui_trigger_tab",
@@ -138,13 +138,13 @@
 
 js_library("cross_device_internals") {
   deps = [
-    ":chime_browser_proxy",
     ":cross_device_logs_browser_proxy",
     ":log_object",
     ":log_types",
     ":logging_tab",
     ":nearby_presence_browser_proxy",
     ":np_list_object",
+    ":push_notification_browser_proxy",
     ":types",
     ":ui_trigger_list_object",
     "//ash/webui/common/resources:cr.m",
@@ -309,7 +309,7 @@
   ]
 }
 
-js_library("chime_browser_proxy") {
+js_library("push_notification_browser_proxy") {
   deps = [
     ":types",
     "//ash/webui/common/resources:cr_deprecated",
diff --git a/chrome/browser/resources/nearby_internals/chime_browser_proxy.js b/chrome/browser/resources/nearby_internals/chime_browser_proxy.js
deleted file mode 100644
index 7316a7ea..0000000
--- a/chrome/browser/resources/nearby_internals/chime_browser_proxy.js
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-export class chimeBrowserProxy {
-  /**
-   * Initializes web contents in the WebUI handler.
-   */
-  initialize() {
-    chrome.send('InitializeChimeHandler');
-  }
-
-  /**
-   * Triggers adding the chime handler as a chime client.
-   */
-  SendAddChimeClient() {
-    chrome.send('AddChimeClient');
-  }
-
-  /** @return {!chimeBrowserProxy} */
-  static getInstance() {
-    return instance || (instance = new chimeBrowserProxy());
-  }
-}
-
-/** @type {?chimeBrowserProxy} */
-let instance = null;
diff --git a/chrome/browser/resources/nearby_internals/cross_device_internals.js b/chrome/browser/resources/nearby_internals/cross_device_internals.js
index 4b595415..da884db 100644
--- a/chrome/browser/resources/nearby_internals/cross_device_internals.js
+++ b/chrome/browser/resources/nearby_internals/cross_device_internals.js
@@ -17,12 +17,12 @@
 import {WebUIListenerBehavior} from 'chrome://resources/ash/common/web_ui_listener_behavior.js';
 import {Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-import {chimeBrowserProxy} from './chime_browser_proxy.js';
 import {getTemplate} from './cross_device_internals.html.js';
 import {NearbyLogsBrowserProxy} from './cross_device_logs_browser_proxy.js';
 import {NearbyPrefsBrowserProxy} from './nearby_prefs_browser_proxy.js';
 import {NearbyPresenceBrowserProxy} from './nearby_presence_browser_proxy.js';
 import {NearbyUiTriggerBrowserProxy} from './nearby_ui_trigger_browser_proxy.js';
+import {PushNotificationBrowserProxy} from './push_notification_browser_proxy.js';
 import {ActionValues, FeatureValues, LogMessage, LogProvider, PresenceDevice, SelectOption, Severity} from './types.js';
 
 
@@ -67,8 +67,8 @@
   /** @private {?NearbyPresenceBrowserProxy} */
   nearbyPresenceBrowserProxy_: null,
 
-  /** @private {?chimeBrowserProxy} */
-  chimeBrowserProxy_: null,
+  /** @private {?PushNotificationBrowserProxy} */
+  PushNotificationBrowserProxy_: null,
 
   /** @private {?NearbyPrefsBrowserProxy}*/
   prefsBrowserProxy_: null,
@@ -91,7 +91,7 @@
         {name: 'Nearby Share', value: FeatureValues.NEARBY_SHARE},
         {name: 'Nearby Connections', value: FeatureValues.NEARBY_CONNECTIONS},
         {name: 'Fast Pair', value: FeatureValues.FAST_PAIR},
-        {name: 'Chime', value: FeatureValues.CHIME},
+        {name: 'Push Notification', value: FeatureValues.PUSH_NOTIFICATION},
       ],
     },
 
@@ -142,10 +142,13 @@
     },
 
     /** @private {!Array<!SelectOption>} */
-    chimeActionList: {
+    pushNotificationActionList: {
       type: Array,
       value: [
-        {name: 'Add Chime Client', value: ActionValues.ADD_CHIME_CLIENT},
+        {
+          name: 'Add Push Notification Client',
+          value: ActionValues.ADD_PUSH_NOTIFICATION_CLIENT,
+        },
       ],
     },
 
@@ -205,7 +208,8 @@
 
   created() {
     this.nearbyPresenceBrowserProxy_ = NearbyPresenceBrowserProxy.getInstance();
-    this.chimeBrowserProxy_ = chimeBrowserProxy.getInstance();
+    this.PushNotificationBrowserProxy_ =
+        PushNotificationBrowserProxy.getInstance();
     this.prefsBrowserProxy_ = NearbyPrefsBrowserProxy.getInstance();
     this.nearbyUITriggerBrowserProxy_ =
         NearbyUiTriggerBrowserProxy.getInstance();
@@ -219,7 +223,7 @@
   attached() {
     this.nearbyPresenceBrowserProxy_.initialize();
     this.nearbyUITriggerBrowserProxy_.initialize();
-    this.chimeBrowserProxy_.initialize();
+    this.PushNotificationBrowserProxy_.initialize();
     this.addWebUIListener(
         'presence-device-found', device => this.onPresenceDeviceFound_(device));
     this.addWebUIListener(
@@ -260,8 +264,8 @@
       case FeatureValues.FAST_PAIR:
         this.set('actionsSelectList', this.fastPairActionList);
         break;
-      case FeatureValues.CHIME:
-        this.set('actionsSelectList', this.chimeActionList);
+      case FeatureValues.PUSH_NOTIFICATION:
+        this.set('actionsSelectList', this.pushNotificationActionList);
         break;
     }
   },
@@ -283,10 +287,10 @@
       case ActionValues.RESET_NEARBY_SHARE:
         this.prefsBrowserProxy_.clearNearbyPrefs();
         break;
-      case ActionValues.ADD_CHIME_CLIENT:
-        this.chimeBrowserProxy_.SendAddChimeClient();
       case ActionValues.SHOW_RECEIVED_NOTIFICATION:
         this.nearbyUITriggerBrowserProxy_.showNearbyShareReceivedNotification();
+      case ActionValues.ADD_PUSH_NOTIFICATION_CLIENT:
+        this.PushNotificationBrowserProxy_.SendAddPushNotificationClient();
       default:
         break;
     }
diff --git a/chrome/browser/resources/nearby_internals/push_notification_browser_proxy.js b/chrome/browser/resources/nearby_internals/push_notification_browser_proxy.js
new file mode 100644
index 0000000..59c15120
--- /dev/null
+++ b/chrome/browser/resources/nearby_internals/push_notification_browser_proxy.js
@@ -0,0 +1,28 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+export class PushNotificationBrowserProxy {
+  /**
+   * Initializes web contents in the WebUI handler.
+   */
+  initialize() {
+    chrome.send('InitializePushNotificationHandler');
+  }
+
+  /**
+   * Triggers adding the push notification handler as a push notification
+   * client.
+   */
+  SendAddPushNotificationClient() {
+    chrome.send('AddPushNotificationClient');
+  }
+
+  /** @return {!PushNotificationBrowserProxy} */
+  static getInstance() {
+    return instance || (instance = new PushNotificationBrowserProxy());
+  }
+}
+
+/** @type {?PushNotificationBrowserProxy} */
+let instance = null;
diff --git a/chrome/browser/resources/nearby_internals/types.js b/chrome/browser/resources/nearby_internals/types.js
index b16106c..2ad71a6d 100644
--- a/chrome/browser/resources/nearby_internals/types.js
+++ b/chrome/browser/resources/nearby_internals/types.js
@@ -12,7 +12,7 @@
   NEARBY_CONNECTIONS: 1,
   NEARBY_PRESENCE: 2,
   FAST_PAIR: 3,
-  CHIME: 4,
+  PUSH_NOTIFICATION: 4,
 };
 
 /**
@@ -26,7 +26,7 @@
   SYNC_CREDENTIALS: 2,
   FIRST_TIME_FLOW: 3,
   RESET_NEARBY_SHARE: 4,
-  ADD_CHIME_CLIENT: 5,
+  ADD_PUSH_NOTIFICATION_CLIENT: 5,
   SHOW_RECEIVED_NOTIFICATION: 6,
 };
 
diff --git a/chrome/browser/resources/new_tab_page/realbox/realbox.html b/chrome/browser/resources/new_tab_page/realbox/realbox.html
index ab601bd7..52338d5 100644
--- a/chrome/browser/resources/new_tab_page/realbox/realbox.html
+++ b/chrome/browser/resources/new_tab_page/realbox/realbox.html
@@ -162,6 +162,31 @@
     width: var(--ntp-realbox-icon-width);
   }
 
+  :host([realbox-chrome-refresh-theming]) .realbox-icon-button {
+    position: static;
+  }
+
+  /* When voice/lens icons are monochrome, they are webkit mask images.
+   * Webkit mask images hide borders so container rules are created to
+   * show focus borders on these icons. */
+  .realbox-icon-button-container {
+    border-radius: 2px;
+    height: 100%;
+    position: absolute;
+    right: 16px;
+    top: 0;
+    z-index: 100;
+  }
+
+  .realbox-icon-button-container.voice {
+    right: var(--ntp-realbox-voice-icon-offset);
+  }
+
+  :host-context(.focus-outline-visible) .realbox-icon-button-container:focus-within {
+    box-shadow: var(--ntp-focus-shadow);
+  }
+
+
   :host(:not([realbox-chrome-refresh-theming])) #voiceSearchButton {
     background-image: url(icons/googlemic_clr_24px.svg);
   }
@@ -208,6 +233,16 @@
     right: unset;
   }
 
+  :host-context([dir='rtl']) .realbox-icon-button-container {
+    left: 16px;
+    right: unset;
+  }
+
+  :host([realbox-lens-search-enabled_]):host-context([dir='rtl']) .realbox-icon-button-container.voice {
+    left: var(--ntp-realbox-voice-icon-offset);
+    right: unset;
+  }
+
   :host-context(.focus-outline-visible) .realbox-icon-button:focus {
     box-shadow: var(--ntp-focus-shadow);
   }
@@ -242,12 +277,28 @@
   <cr-realbox-icon id="icon" match="[[selectedMatch_]]"
       default-icon="[[realboxIcon_]]" in-searchbox>
   </cr-realbox-icon>
-  <button id="voiceSearchButton" class="realbox-icon-button"
+  <div class="realbox-icon-button-container voice"
+      hidden="[[!realboxChromeRefreshTheming]]">
+    <button id="voiceSearchButton" class="realbox-icon-button"
         on-click="onVoiceSearchClick_" title="$i18n{voiceSearchButtonLabel}">
+    </button>
+  </div>
+  <div class="realbox-icon-button-container lens"
+      hidden="[[!realboxChromeRefreshTheming]]">
+    <template is="dom-if" if="[[realboxLensSearchEnabled_]]">
+      <button id="lensSearchButton" class="realbox-icon-button"
+          on-click="onLensSearchClick_" title="$i18n{lensSearchButtonLabel}">
+      </button>
+    </template>
+  </div>
+  <button id="voiceSearchButton" class="realbox-icon-button"
+      on-click="onVoiceSearchClick_" title="$i18n{voiceSearchButtonLabel}"
+      hidden="[[realboxChromeRefreshTheming]]">
   </button>
   <template is="dom-if" if="[[realboxLensSearchEnabled_]]">
     <button id="lensSearchButton" class="realbox-icon-button"
-        on-click="onLensSearchClick_" title="$i18n{lensSearchButtonLabel}">
+        on-click="onLensSearchClick_" title="$i18n{lensSearchButtonLabel}"
+        hidden="[[realboxChromeRefreshTheming]]">
     </button>
   </template>
   <cr-realbox-dropdown id="matches" role="listbox" result="[[result_]]"
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.ts b/chrome/browser/resources/settings/basic_page/basic_page.ts
index aaca351..52744f0 100644
--- a/chrome/browser/resources/settings/basic_page/basic_page.ts
+++ b/chrome/browser/resources/settings/basic_page/basic_page.ts
@@ -376,7 +376,7 @@
         this.showPage_(visibility);
   }
 
-  private onMemorySaverFeedbackClick_(e: Event) {
+  private onSendMemorySaverFeedbackClick_(e: Event) {
     e.stopPropagation();
     this.performanceBrowserProxy_.openMemorySaverFeedbackDialog();
   }
diff --git a/chrome/browser/resources/settings/privacy_page/OWNERS b/chrome/browser/resources/settings/privacy_page/OWNERS
index 14f78c7c..c393996 100644
--- a/chrome/browser/resources/settings/privacy_page/OWNERS
+++ b/chrome/browser/resources/settings/privacy_page/OWNERS
@@ -1,3 +1,5 @@
 sauski@google.com
 rainhard@chromium.org
 sideyilmaz@chromium.org
+
+per-file cookies_page*=fmacintosh@google.com
diff --git a/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/combobox/customize_chrome_combobox.html b/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/combobox/customize_chrome_combobox.html
index 7e94918..ab53be4c 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/combobox/customize_chrome_combobox.html
+++ b/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/combobox/customize_chrome_combobox.html
@@ -54,6 +54,70 @@
 #dropdown::-webkit-scrollbar-thumb {
   background: var(--color-side-panel-scrollbar-thumb);
 }
+
+.group-item {
+  display: flex;
+  font-weight: 700;
+}
+
+.group-item iron-icon {
+  --iron-icon-height: 16px;
+  --iron-icon-width: 16px;
+  margin-inline-start: auto;
+}
+
+.group-item,
+.item {
+  align-items: center;
+  box-sizing: border-box;
+  border: none;
+  display: flex;
+  height: 28px;
+  padding: 0 20px;
+}
+
+.group-item[highlighted],
+.item[highlighted] {
+  background: var(--cr-active-neutral-on-subtle-background-color);
+}
+
+.item iron-icon {
+  --iron-icon-height: 16px;
+  --iron-icon-width: 16px;
+  flex-shrink: 0;
+  visibility: hidden;
+  margin-inline-end: 8px;
+}
+
+.item[selected] iron-icon {
+  visibility: visible;
+}
+
+.item:has(img) {
+  height: 48px;
+}
+
+.item customize-chrome-check-mark-wrapper {
+  --customize-chrome-check-mark-wrapper-end: -8px;
+  --customize-chrome-check-mark-wrapper-size: 16px;
+  --customize-chrome-check-mark-wrapper-top: -3px;
+}
+
+.item img {
+  border-radius: 8px;
+  height: 40px;
+  width: 40px;
+}
+
+.item span {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.item:has(img) span {
+  padding-inline-start: 16px;
+}
 </style>
 
 <button id="input" class="md-select"
@@ -71,6 +135,37 @@
       on-pointerdown="onDropdownPointerdown_"
       on-pointermove="onDropdownPointermove_"
       on-pointerover="onDropdownPointerover_">
-    <slot></slot>
+    <template is="dom-repeat" items="[[items]]" restamp>
+      <template is="dom-if" if="[[isGroup_(item)]]" restamp>
+        <div class="group" role="group">
+          <label class="group-item" on-click="onGroupClick_">
+            [[item.label]]
+            <iron-icon icon="[[getGroupIcon_(index, expandedGroups_.*)]]">
+            </iron-icon>
+          </label>
+          <template is="dom-if" restamp if="[[isGroupExpanded_(index, expandedGroups_.*)]]">
+            <template is="dom-repeat" items="[[item.items]]" as="subitem">
+              <div class="item" role="option" value="[[subitem.label]]">
+                <iron-icon icon="cr:check"></iron-icon>
+                <span>[[subitem.label]]</span>
+              </div>
+            </template>
+          </template>
+        </div>
+      </template>
+
+      <template is="dom-if" if="[[!isGroup_(item)]]" restamp>
+        <div class="item" role="option" value="[[item.label]]">
+          <template is="dom-if" if="[[item.imagePath]]">
+            <customize-chrome-check-mark-wrapper
+                checked="[[isItemSelected_(item, value)]]">
+              <img is="cr-auto-img" auto-src="[[item.imagePath]]"></img>
+            </customize-chrome-check-mark-wrapper>
+          </template>
+          <iron-icon icon="cr:check" hidden$="[[item.imagePath]]"></iron-icon>
+          <span>[[item.label]]</span>
+        </div>
+      </template>
+    </template>
   </div>
 </div>
diff --git a/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/combobox/customize_chrome_combobox.ts b/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/combobox/customize_chrome_combobox.ts
index 33b8788..2770cecc 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/combobox/customize_chrome_combobox.ts
+++ b/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/combobox/customize_chrome_combobox.ts
@@ -5,7 +5,7 @@
 import 'chrome://resources/cr_elements/md_select.css.js';
 import 'chrome://resources/cr_elements/cr_shared_vars.css.js';
 
-import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {afterNextRender, DomRepeatEvent, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {getTemplate} from './customize_chrome_combobox.html.js';
 
@@ -17,6 +17,16 @@
 
 export type OptionElement = HTMLElement&{value?: string};
 
+export interface ComboboxItem {
+  label: string;
+  imagePath?: string;
+}
+
+export interface ComboboxGroup {
+  label: string;
+  items: ComboboxItem[];
+}
+
 /* Running count of total items. Incremented to provide unique IDs. */
 let itemCount = 0;
 
@@ -44,7 +54,12 @@
         reflectToAttribute: true,
         observer: 'onExpandedChange_',
       },
+      expandedGroups_: Object,
       highlightedElement_: Object,
+      items: {
+        type: Array,
+        value: () => [],
+      },
       label: String,
       rightAlignDropbox: {
         type: Boolean,
@@ -64,8 +79,10 @@
   }
 
   private expanded_: boolean;
+  private expandedGroups_: {[groupIndex: number]: boolean} = {};
   private highlightableElements_: HTMLElement[] = [];
   private highlightedElement_: HTMLElement|null = null;
+  items: ComboboxGroup[]|ComboboxItem[];
   label: string;
   private lastHighlightWasByKeyboard_: boolean = false;
   private domObserver_: MutationObserver|null = null;
@@ -80,7 +97,8 @@
     // elements. Note that a slotchange event does not work here since
     // slotchange only listens for changes to direct children of the component.
     this.domObserver_ = new MutationObserver(this.onDomChange_.bind(this));
-    this.domObserver_.observe(this, {childList: true, subtree: true});
+    this.domObserver_.observe(
+        this.$.dropdown, {attributes: false, childList: true, subtree: true});
 
     // Call the observer's callback once to initialize.
     this.onDomChange_();
@@ -96,6 +114,11 @@
     return this.highlightedElement_?.id;
   }
 
+  private getGroupIcon_(groupIndex: number): string {
+    return this.expandedGroups_[groupIndex] ? 'cr:expand-less' :
+                                              'cr:expand-more';
+  }
+
   private getInputLabel_(): string {
     if (this.selectedElement_) {
       return this.selectedElement_.textContent!;
@@ -121,9 +144,22 @@
     this.lastHighlightWasByKeyboard_ = byKeyboard;
   }
 
+  private isGroup_(item: ComboboxGroup|ComboboxItem): boolean {
+    return item.hasOwnProperty('items');
+  }
+
+  private isGroupExpanded_(groupIndex: number): boolean {
+    return this.expandedGroups_[groupIndex];
+  }
+
+  private isItemSelected_(item: ComboboxItem): boolean {
+    return this.value === item.label;
+  }
+
   private onDomChange_() {
-    this.highlightableElements_ = Array.from(
-        this.querySelectorAll<HTMLElement>(HIGHLIGHTABLE_ITEMS_SELECTOR));
+    this.highlightableElements_ =
+        Array.from(this.shadowRoot!.querySelectorAll<HTMLElement>(
+            HIGHLIGHTABLE_ITEMS_SELECTOR));
 
     this.highlightableElements_.forEach(element => {
       if (!element.id) {
@@ -198,6 +234,11 @@
     this.highlightElement_(this.selectedElement_, false);
   }
 
+  private onGroupClick_(e: DomRepeatEvent<ComboboxGroup>) {
+    const index = e.model.index;
+    this.set(`expandedGroups_.${index}`, !this.expandedGroups_[index]);
+  }
+
   private onInputClick_() {
     this.expanded_ = !this.expanded_;
   }
@@ -312,11 +353,22 @@
       return;
     }
 
-    this.selectItem_(
-        (Array.from(this.querySelectorAll(SELECTABLE_ITEMS_SELECTOR)) as
-         OptionElement[])
-            .find(option => option.value === this.value) ||
-        null);
+    const selectedGroupIndex =
+        this.items.filter(item => this.isGroup_(item)).findIndex((group) => {
+          return (group as ComboboxGroup)
+              .items.find((item) => item.label === this.value);
+        });
+    if (selectedGroupIndex > -1) {
+      this.set(`expandedGroups_.${selectedGroupIndex}`, true);
+    }
+
+    afterNextRender(this, () => {
+      this.selectItem_(
+          (Array.from(this.shadowRoot!.querySelectorAll(
+               SELECTABLE_ITEMS_SELECTOR)) as OptionElement[])
+              .find(option => option.value === this.value) ||
+          null);
+    });
   }
 
   private selectItem_(item: HTMLElement|null): boolean {
diff --git a/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.html b/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.html
index 6c587854..07a8bf8 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.html
+++ b/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.html
@@ -56,50 +56,6 @@
     width: 100%;
   }
 
-  .category-item {
-    display: flex;
-    font-weight: 700;
-  }
-
-  .category-item iron-icon {
-    --iron-icon-height: 16px;
-    --iron-icon-width: 16px;
-    margin-inline-start: auto;
-  }
-
-  .category-item,
-  .dropdown-item {
-    align-items: center;
-    box-sizing: border-box;
-    border: none;
-    display: flex;
-    height: 28px;
-    padding: 0 20px;
-  }
-
-  .category-item[highlighted],
-  .dropdown-item[highlighted] {
-    background: var(--cr-active-neutral-on-subtle-background-color);
-  }
-
-  .dropdown-item iron-icon {
-    --iron-icon-height: 16px;
-    --iron-icon-width: 16px;
-    flex-shrink: 0;
-    visibility: hidden;
-    margin-inline-end: 8px;
-  }
-
-  .dropdown-item[selected] iron-icon {
-    visibility: visible;
-  }
-
-  .dropdown-item span {
-    overflow: hidden;
-    text-overflow: ellipsis;
-    white-space: nowrap;
-  }
-
   #optionalDetails {
     display: flex;
     flex-wrap: wrap;
@@ -124,26 +80,6 @@
     flex-grow: 1;
   }
 
-  #descriptorComboboxB .dropdown-item {
-    height: 48px;
-  }
-
-  #descriptorComboboxB customize-chrome-check-mark-wrapper {
-    --customize-chrome-check-mark-wrapper-end: -8px;
-    --customize-chrome-check-mark-wrapper-size: 16px;
-    --customize-chrome-check-mark-wrapper-top: -3px;
-  }
-
-  #descriptorComboboxB img {
-    border-radius: 8px;
-    height: 40px;
-    width: 40px;
-  }
-
-  #descriptorComboboxB span {
-    padding-inline-start: 16px;
-  }
-
   #descriptorMenuD {
     --cr-column-width: 1fr;
     --cr-grid-gap: 6.5px;
@@ -328,52 +264,20 @@
       tabindex="-1">
     <customize-chrome-combobox id="descriptorComboboxA"
         label="$i18n{wallpaperSearchSubjectLabel}"
+        items="[[comboboxItems_.a]]"
         value="{{selectedDescriptorA_}}">
-      <template is="dom-repeat" items="[[descriptors_.descriptorA]]">
-        <div class="category" role="group">
-          <label class="category-item" on-click="onComboboxCategoryClick_">
-            [[item.category]]
-            <iron-icon icon="[[
-                getCategoryIcon_(index, expandedCategories_.*)]]">
-            </iron-icon>
-          </label>
-          <template is="dom-if" restamp if="[[
-              isCategoryExpanded_(index, expandedCategories_.*)]]">
-            <template is="dom-repeat" items="[[item.labels]]">
-              <div class="dropdown-item" role="option" value="[[item]]">
-                <iron-icon icon="cr:check"></iron-icon>
-                <span>[[item]]</span>
-              </div>
-            </template>
-          </template>
-        </div>
-      </template>
     </customize-chrome-combobox>
     <div id="optionalDetails">
       <div id="optionalDetailsLabel">$i18n{optionalDetailsLabel}</div>
       <customize-chrome-combobox id="descriptorComboboxB"
           label="$i18n{wallpaperSearchStyleLabel}"
+          items="[[comboboxItems_.b]]"
           value="{{selectedDescriptorB_}}">
-        <template is="dom-repeat" items="[[descriptors_.descriptorB]]">
-          <div class="dropdown-item" role="option" value="[[item.label]]">
-            <customize-chrome-check-mark-wrapper
-                checked="[[isOptionSelectedInDescriptorB_(
-                    item, selectedDescriptorB_)]]">
-              <img is="cr-auto-img" auto-src="[[item.imagePath]]"></img>
-            </customize-chrome-check-mark-wrapper>
-            <span>[[item.label]]</span>
-          </div>
-        </template>
       </customize-chrome-combobox>
       <customize-chrome-combobox id="descriptorComboboxC"
           label="$i18n{wallpaperSearchMoodLabel}"
+          items="[[comboboxItems_.c]]"
           value="{{selectedDescriptorC_}}" right-align-dropbox>
-        <template is="dom-repeat" items="[[descriptors_.descriptorC]]">
-          <div class="dropdown-item" role="option" value="[[item]]">
-            <iron-icon icon="cr:check"></iron-icon>
-            <span>[[item]]</span>
-          </div>
-        </template>
       </customize-chrome-combobox>
       <cr-grid columns="6" id="descriptorMenuD">
         <template is="dom-repeat" items="[[descriptorD_]]">
diff --git a/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.ts b/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.ts
index 00bec5e9..9d436fb 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.ts
+++ b/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.ts
@@ -37,7 +37,7 @@
 import {DescriptorA, DescriptorB, DescriptorDValue, Descriptors, UserFeedback, WallpaperSearchClientCallbackRouter, WallpaperSearchHandlerInterface, WallpaperSearchResult, WallpaperSearchStatus} from '../wallpaper_search.mojom-webui.js';
 import {WindowProxy} from '../window_proxy.js';
 
-import {CustomizeChromeCombobox} from './combobox/customize_chrome_combobox.js';
+import {ComboboxGroup, ComboboxItem, CustomizeChromeCombobox} from './combobox/customize_chrome_combobox.js';
 import {getTemplate} from './wallpaper_search.html.js';
 import {WallpaperSearchProxy} from './wallpaper_search_proxy.js';
 
@@ -76,6 +76,12 @@
   c?: string|null;
 }
 
+interface ComboxItems {
+  a: ComboboxGroup[];
+  b: ComboboxItem[];
+  c: ComboboxItem[];
+}
+
 export interface ErrorState {
   title: string;
   description: string;
@@ -120,6 +126,7 @@
 
   static get properties() {
     return {
+      comboboxItems_: Array,
       descriptors_: {
         type: Object,
         value: null,
@@ -180,6 +187,7 @@
     };
   }
 
+  private comboboxItems_: ComboxItems|null;
   private descriptors_: Descriptors|null;
   private descriptorD_: string[];
   private emptyHistoryContainers_: number[] = [];
@@ -309,6 +317,20 @@
     this.wallpaperSearchHandler_.getDescriptors().then(({descriptors}) => {
       if (descriptors) {
         this.descriptors_ = descriptors;
+        this.comboboxItems_ = {
+          a: descriptors.descriptorA.map((group) => {
+            return {
+              label: group.category,
+              items: group.labels.map((label) => {
+                return {label};
+              }),
+            };
+          }),
+          b: descriptors.descriptorB,
+          c: descriptors.descriptorC.map((label) => {
+            return {label};
+          }),
+        };
         this.errorCallback_ = undefined;
       } else {
         this.errorCallback_ = () => this.fetchDescriptors_();
@@ -363,11 +385,6 @@
     return this.isBackgroundSelected_(id) ? 'true' : 'false';
   }
 
-  private getCategoryIcon_(categoryIndex: number): string {
-    return this.expandedCategories_[categoryIndex] ? 'cr:expand-less' :
-                                                     'cr:expand-more';
-  }
-
   private getColorCheckedStatus_(defaultColor: string): string {
     return this.isColorSelected_(defaultColor) ? 'true' : 'false';
   }
@@ -414,10 +431,6 @@
         this.theme_.backgroundImage.localBackgroundId.high === id.high);
   }
 
-  private isCategoryExpanded_(categoryIndex: number): boolean {
-    return this.expandedCategories_[categoryIndex];
-  }
-
   private isColorSelected_(defaultColor: string): boolean {
     return defaultColor === this.selectedDefaultColor_;
   }
diff --git a/chrome/browser/resources/side_panel/read_anything/app.ts b/chrome/browser/resources/side_panel/read_anything/app.ts
index ac7da689..baf5c4a 100644
--- a/chrome/browser/resources/side_panel/read_anything/app.ts
+++ b/chrome/browser/resources/side_panel/read_anything/app.ts
@@ -203,8 +203,6 @@
   speechStarted = false;
   maxSpeechLength = 175;
 
-  // TODO(crbug.com/1474951): Make this the screen reader default speed if a
-  // TTS speed has been set
   rate: number = 1;
 
   constructor() {
@@ -633,7 +631,6 @@
     };
 
     message.onend = () => {
-      // TODO(crbug.com/1474951): Add toggle to turn off highlight.
       // TODO(crbug.com/1474951): Handle already selected text.
       // TODO(crbug.com/1474951): Return text to its original style once
       // the document has finished.
diff --git a/chrome/browser/resources/tab_search/tab_organization_page.html b/chrome/browser/resources/tab_search/tab_organization_page.html
index 1eb48fd8f..4944a5b 100644
--- a/chrome/browser/resources/tab_search/tab_organization_page.html
+++ b/chrome/browser/resources/tab_search/tab_organization_page.html
@@ -10,14 +10,6 @@
     display: flex;
   }
 
-  tab-organization-not-started[shown],
-  tab-organization-in-progress[shown],
-  tab-organization-results[shown],
-  tab-organization-failure[shown] {
-    animation: fadeIn 200ms linear forwards,
-               paddingIn 250ms var(--standard-curve) forwards;
-  }
-
   :host(.changed-state) tab-organization-not-started[shown],
   :host(.changed-state) tab-organization-in-progress[shown],
   :host(.changed-state) tab-organization-results[shown],
diff --git a/chrome/browser/resources/tab_search/tab_search_page.html b/chrome/browser/resources/tab_search/tab_search_page.html
index d814bf78..020c20d 100644
--- a/chrome/browser/resources/tab_search/tab_search_page.html
+++ b/chrome/browser/resources/tab_search/tab_search_page.html
@@ -1,18 +1,4 @@
 <style include="mwb-shared-style tab-organization-shared-style">
-  :host {
-    --standard-curve: cubic-bezier(0.2, 0.0, 0, 1.0);
-  }
-
-  :host([tab-organization-enabled]:is(.iron-selected)) #tabSearchPage {
-    animation: fadeIn 200ms linear, paddingIn 250ms var(--standard-curve);
-    opacity: 1;
-  }
-
-  :host([tab-organization-enabled]:not(.iron-selected)) #tabSearchPage {
-    animation: fadeOut 200ms linear, marginOut 250ms var(--standard-curve);
-    opacity: 0;
-  }
-
   #searchField {
     align-items: center;
     background-color: var(--mwb-background-color);
diff --git a/chrome/browser/resources/tab_search/tab_search_page.ts b/chrome/browser/resources/tab_search/tab_search_page.ts
index 73fe997..c529a8b3 100644
--- a/chrome/browser/resources/tab_search/tab_search_page.ts
+++ b/chrome/browser/resources/tab_search/tab_search_page.ts
@@ -10,7 +10,6 @@
 import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
 import 'chrome://resources/polymer/v3_0/iron-iconset-svg/iron-iconset-svg.js';
 import './infinite_list.js';
-import './tab_organization_shared_style.css.js';
 import './tab_search_group_item.js';
 import './tab_search_item.js';
 import './title_item.js';
diff --git a/chrome/browser/resources/vr/DIR_METADATA b/chrome/browser/resources/vr/DIR_METADATA
deleted file mode 100644
index f4b55f85..0000000
--- a/chrome/browser/resources/vr/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail: {
-  component: "UI>Browser>VR"
-}
-team_email: "xr-dev@chromium.org"
diff --git a/chrome/browser/resources/vr/OWNERS b/chrome/browser/resources/vr/OWNERS
deleted file mode 100644
index da26124..0000000
--- a/chrome/browser/resources/vr/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-file://components/webxr/OWNERS
-tiborg@chromium.org
diff --git a/chrome/browser/resources/vr/assets/PRESUBMIT.py b/chrome/browser/resources/vr/assets/PRESUBMIT.py
deleted file mode 100644
index adeaeed..0000000
--- a/chrome/browser/resources/vr/assets/PRESUBMIT.py
+++ /dev/null
@@ -1,107 +0,0 @@
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-
-import sys
-
-
-def IsNewer(old_version, new_version):
-  return (old_version and new_version and
-          (old_version.major < new_version.major or
-           (old_version.major == new_version.major and
-            old_version.minor < new_version.minor)))
-
-
-def CheckVersionAndAssetParity(input_api, output_api):
-  """Checks that
-  - the version was upraded if assets files were changed,
-  - the version was not downgraded,
-  - both the google_chrome and the chromium assets have the same files.
-  """
-  sys.path.append(input_api.PresubmitLocalPath())
-  import parse_version
-
-  old_version = None
-  new_version = None
-  changed_assets = False
-  changed_version = False
-  changed_component_list = False
-  changed_asset_files = {'google_chrome': [], 'chromium': []}
-  for file in input_api.AffectedFiles():
-    basename = input_api.os_path.basename(file.LocalPath())
-    extension = input_api.os_path.splitext(basename)[1][1:].strip().lower()
-    basename_without_extension = input_api.os_path.splitext(basename)[
-        0].strip().lower()
-    if extension == 'sha1':
-      basename_without_extension = input_api.os_path.splitext(
-          basename_without_extension)[0]
-    dirname = input_api.os_path.basename(
-        input_api.os_path.dirname(file.LocalPath()))
-    action = file.Action()
-    if (dirname in changed_asset_files and
-        extension in {'sha1', 'png', 'wav'} and action in {'A', 'D'}):
-      changed_asset_files[dirname].append((action, basename_without_extension))
-    if (extension == 'sha1' or basename == 'vr_assets_component_files.json'):
-      # See if there are actually changes or if it's just --files or --all:
-      if file.ChangedContents():
-        changed_assets = True
-    if basename == 'vr_assets_component_files.json':
-      changed_component_list = True
-    if basename == 'VERSION':
-      old_version = parse_version.ParseVersion(file.OldContents())
-      new_version = parse_version.ParseVersion(file.NewContents())
-      if new_version != old_version:
-        changed_version = True
-
-  local_version_filename = input_api.os_path.join(
-      input_api.os_path.dirname(input_api.AffectedFiles()[0].LocalPath()),
-      'VERSION')
-  local_component_list_filename = input_api.os_path.join(
-      input_api.os_path.dirname(input_api.AffectedFiles()[0].LocalPath()),
-      'vr_assets_component_files.json')
-
-  if changed_asset_files['google_chrome'] != changed_asset_files['chromium']:
-    return [
-        output_api.PresubmitError(
-            'Must have same asset files for %s in \'%s\'.' %
-            (changed_asset_files.keys(),
-             input_api.os_path.dirname(
-                 input_api.AffectedFiles()[0].LocalPath())))
-    ]
-
-  if changed_asset_files['google_chrome'] and not changed_component_list:
-    return [
-        output_api.PresubmitError(
-            'Must update \'%s\' if adding/removing assets.' %
-            local_component_list_filename)
-    ]
-
-  if changed_version and (not old_version or not new_version):
-    return [
-        output_api.PresubmitError(
-            'Cannot parse version in \'%s\'.' % local_version_filename)
-    ]
-
-  version_upgraded = IsNewer(old_version, new_version)
-  if changed_assets and not version_upgraded:
-    return [
-        output_api.PresubmitError(
-            'Must increment version in \'%s\' when '
-            'updating VR assets.' % local_version_filename)
-    ]
-  if changed_version and not version_upgraded:
-    return [
-        output_api.PresubmitError(
-            'Must not downgrade version in \'%s\'.' % local_version_filename)
-    ]
-
-  return []
-
-
-def CheckChangeOnUpload(input_api, output_api):
-  return CheckVersionAndAssetParity(input_api, output_api)
-
-
-def CheckChangeOnCommit(input_api, output_api):
-  return CheckVersionAndAssetParity(input_api, output_api)
diff --git a/chrome/browser/resources/vr/assets/VERSION b/chrome/browser/resources/vr/assets/VERSION
deleted file mode 100644
index 4fc45d1..0000000
--- a/chrome/browser/resources/vr/assets/VERSION
+++ /dev/null
@@ -1,2 +0,0 @@
-MAJOR=2
-MINOR=3
\ No newline at end of file
diff --git a/chrome/browser/resources/vr/assets/chromium/back_button_click.wav b/chrome/browser/resources/vr/assets/chromium/back_button_click.wav
deleted file mode 100644
index e0f4f20..0000000
--- a/chrome/browser/resources/vr/assets/chromium/back_button_click.wav
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/vr/assets/chromium/background.png b/chrome/browser/resources/vr/assets/chromium/background.png
deleted file mode 100644
index 0fb3bfc3..0000000
--- a/chrome/browser/resources/vr/assets/chromium/background.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/vr/assets/chromium/button_click.wav b/chrome/browser/resources/vr/assets/chromium/button_click.wav
deleted file mode 100644
index 12661f5..0000000
--- a/chrome/browser/resources/vr/assets/chromium/button_click.wav
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/vr/assets/chromium/button_hover.wav b/chrome/browser/resources/vr/assets/chromium/button_hover.wav
deleted file mode 100644
index 3176f4cb..0000000
--- a/chrome/browser/resources/vr/assets/chromium/button_hover.wav
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/vr/assets/chromium/fullscreen_gradient.png b/chrome/browser/resources/vr/assets/chromium/fullscreen_gradient.png
deleted file mode 100644
index 04c5d88..0000000
--- a/chrome/browser/resources/vr/assets/chromium/fullscreen_gradient.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/vr/assets/chromium/inactive_button_click.wav b/chrome/browser/resources/vr/assets/chromium/inactive_button_click.wav
deleted file mode 100644
index a6bd2c4..0000000
--- a/chrome/browser/resources/vr/assets/chromium/inactive_button_click.wav
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/vr/assets/chromium/incognito_gradient.png b/chrome/browser/resources/vr/assets/chromium/incognito_gradient.png
deleted file mode 100644
index 4fb1749..0000000
--- a/chrome/browser/resources/vr/assets/chromium/incognito_gradient.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/vr/assets/chromium/normal_gradient.png b/chrome/browser/resources/vr/assets/chromium/normal_gradient.png
deleted file mode 100644
index 0fb3bfc3..0000000
--- a/chrome/browser/resources/vr/assets/chromium/normal_gradient.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/vr/assets/google_chrome/back_button_click.wav.sha1 b/chrome/browser/resources/vr/assets/google_chrome/back_button_click.wav.sha1
deleted file mode 100644
index 638bbcb..0000000
--- a/chrome/browser/resources/vr/assets/google_chrome/back_button_click.wav.sha1
+++ /dev/null
@@ -1 +0,0 @@
-739b9d5d9d6671242b79ce0b5ccfb8b4d9a7eb4a
\ No newline at end of file
diff --git a/chrome/browser/resources/vr/assets/google_chrome/background.png.sha1 b/chrome/browser/resources/vr/assets/google_chrome/background.png.sha1
deleted file mode 100644
index d3427cb..0000000
--- a/chrome/browser/resources/vr/assets/google_chrome/background.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-e148d023e6ff397240f9db31063c3f2c5888f39e
\ No newline at end of file
diff --git a/chrome/browser/resources/vr/assets/google_chrome/button_click.wav.sha1 b/chrome/browser/resources/vr/assets/google_chrome/button_click.wav.sha1
deleted file mode 100644
index c319deb..0000000
--- a/chrome/browser/resources/vr/assets/google_chrome/button_click.wav.sha1
+++ /dev/null
@@ -1 +0,0 @@
-ee6bfbbcc1ea33e6ff448820fadc91bd53f562a0
\ No newline at end of file
diff --git a/chrome/browser/resources/vr/assets/google_chrome/button_hover.wav.sha1 b/chrome/browser/resources/vr/assets/google_chrome/button_hover.wav.sha1
deleted file mode 100644
index ac5cdbed..0000000
--- a/chrome/browser/resources/vr/assets/google_chrome/button_hover.wav.sha1
+++ /dev/null
@@ -1 +0,0 @@
-e4089035e81c181d98bc7aeaa9e3c6607a8f7cf4
\ No newline at end of file
diff --git a/chrome/browser/resources/vr/assets/google_chrome/fullscreen_gradient.png.sha1 b/chrome/browser/resources/vr/assets/google_chrome/fullscreen_gradient.png.sha1
deleted file mode 100644
index 201ca21a..0000000
--- a/chrome/browser/resources/vr/assets/google_chrome/fullscreen_gradient.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-be61cbcdc981d5592455d3b7a14b97e14d3acac4
\ No newline at end of file
diff --git a/chrome/browser/resources/vr/assets/google_chrome/inactive_button_click.wav.sha1 b/chrome/browser/resources/vr/assets/google_chrome/inactive_button_click.wav.sha1
deleted file mode 100644
index c5bb4ae..0000000
--- a/chrome/browser/resources/vr/assets/google_chrome/inactive_button_click.wav.sha1
+++ /dev/null
@@ -1 +0,0 @@
-e75d3a135c48f42fea2272174ecdf2a562f18864
\ No newline at end of file
diff --git a/chrome/browser/resources/vr/assets/google_chrome/incognito_gradient.png.sha1 b/chrome/browser/resources/vr/assets/google_chrome/incognito_gradient.png.sha1
deleted file mode 100644
index 1282cf1..0000000
--- a/chrome/browser/resources/vr/assets/google_chrome/incognito_gradient.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-6b0e506b19b79ec1be4963a9bd92ab8b92ccca1c
\ No newline at end of file
diff --git a/chrome/browser/resources/vr/assets/google_chrome/normal_gradient.png.sha1 b/chrome/browser/resources/vr/assets/google_chrome/normal_gradient.png.sha1
deleted file mode 100644
index 94c792b..0000000
--- a/chrome/browser/resources/vr/assets/google_chrome/normal_gradient.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-446510d78dc522fcef45cb88a7a7c4c6d72e17ed
\ No newline at end of file
diff --git a/chrome/browser/resources/vr/assets/parse_version.py b/chrome/browser/resources/vr/assets/parse_version.py
deleted file mode 100644
index 29ef14b9..0000000
--- a/chrome/browser/resources/vr/assets/parse_version.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import collections
-
-
-def ParseVersion(lines):
-  version_keys = ['MAJOR', 'MINOR']
-  version_vals = {}
-  for line in lines:
-    key, val = line.strip().split('=', 1)
-    if key in version_keys:
-      if key in version_vals or not val.isdigit():
-        return None
-      version_vals[key] = int(val)
-
-  if set(version_keys) != set(version_vals):
-    # We didn't see all parts of the version.
-    return None
-
-  return collections.namedtuple('Version', ['major', 'minor'])(
-      major=version_vals['MAJOR'], minor=version_vals['MINOR'])
diff --git a/chrome/browser/resources/vr/assets/push_assets_component.py b/chrome/browser/resources/vr/assets/push_assets_component.py
deleted file mode 100755
index d11f2810..0000000
--- a/chrome/browser/resources/vr/assets/push_assets_component.py
+++ /dev/null
@@ -1,86 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# Build and push the {version}/{platform}/vr-assets.zip file to GCS so
-# that the component update system will pick them up and push them
-# to users.
-#
-# Requires gsutil to be in the user's path.
-
-import os
-import shutil
-import subprocess
-import sys
-import zipfile
-import zlib
-import json
-import tempfile
-import parse_version
-
-DEST_BUCKET = 'gs://chrome-component-vr-assets'
-PLATFORM = 'android'
-
-
-class TempDir():
-
-  def __enter__(self):
-    self._dirpath = tempfile.mkdtemp()
-    return self._dirpath
-
-  def __exit__(self, type, value, traceback):
-    shutil.rmtree(self._dirpath)
-
-
-def PrintInfo(header, items):
-  print('\n%s' % header)
-  print '   ', '\n    '.join(items)
-
-
-def main():
-  assets_dir = os.path.dirname(os.path.abspath(__file__))
-
-  files = []
-  with open(os.path.join(assets_dir,
-                         'vr_assets_component_files.json')) as json_file:
-    files = json.load(json_file)
-
-  version = None
-  with open(os.path.join(assets_dir, 'VERSION')) as version_file:
-    version = parse_version.ParseVersion(version_file.readlines())
-  assert version
-
-  PrintInfo('Version', ['%s.%s' % (version.major, version.minor)])
-  PrintInfo('Platform', [PLATFORM])
-  PrintInfo('Asset files', files)
-
-  with TempDir() as temp_dir:
-    zip_dir = os.path.join(temp_dir, '%s.%s' % (version.major, version.minor),
-                           PLATFORM)
-    zip_path = os.path.join(zip_dir, 'vr-assets.zip')
-
-    os.makedirs(zip_dir)
-    zip_files = []
-    with zipfile.ZipFile(zip_path, 'w') as zip:
-      for file in files:
-        file_path = os.path.join(assets_dir, file)
-        zip.write(file_path, os.path.basename(file_path), zipfile.ZIP_DEFLATED)
-      for info in zip.infolist():
-        zip_files.append(info.filename)
-
-    # Upload component.
-    command = ['gsutil', 'cp', '-nR', '.', DEST_BUCKET]
-    PrintInfo('Going to run the following command', [' '.join(command)])
-    PrintInfo('In directory', [temp_dir])
-    PrintInfo('Which pushes the following file', [zip_path])
-    PrintInfo('Which contains the files', zip_files)
-
-    if raw_input('\nAre you sure (y/N) ').lower() != 'y':
-      print 'aborting'
-      return 1
-    return subprocess.call(command, cwd=temp_dir)
-
-
-if __name__ == '__main__':
-  sys.exit(main())
diff --git a/chrome/browser/resources/vr/assets/vr_assets_component_files.json b/chrome/browser/resources/vr/assets/vr_assets_component_files.json
deleted file mode 100644
index e6dfab0f..0000000
--- a/chrome/browser/resources/vr/assets/vr_assets_component_files.json
+++ /dev/null
@@ -1,10 +0,0 @@
-[
-  "google_chrome/background.png",
-  "google_chrome/fullscreen_gradient.png",
-  "google_chrome/incognito_gradient.png",
-  "google_chrome/normal_gradient.png",
-  "google_chrome/button_click.wav",
-  "google_chrome/button_hover.wav",
-  "google_chrome/back_button_click.wav",
-  "google_chrome/inactive_button_click.wav"
-]
\ No newline at end of file
diff --git a/chrome/browser/smart_card/smart_card_permission_request.cc b/chrome/browser/smart_card/smart_card_permission_request.cc
index c54e3aa1..6c975a0 100644
--- a/chrome/browser/smart_card/smart_card_permission_request.cc
+++ b/chrome/browser/smart_card/smart_card_permission_request.cc
@@ -39,6 +39,11 @@
                                     base::ASCIIToUTF16(reader_name_));
 }
 
+std::optional<std::u16string> SmartCardPermissionRequest::GetAllowAlwaysText()
+    const {
+  return l10n_util::GetStringUTF16(IDS_SMART_CARD_PERMISSION_ALWAYS_ALLOW);
+}
+
 void SmartCardPermissionRequest::OnPermissionDecided(
     ContentSetting content_setting_result,
     bool is_one_time,
diff --git a/chrome/browser/smart_card/smart_card_permission_request.h b/chrome/browser/smart_card/smart_card_permission_request.h
index 27d9c1e..c5e1685 100644
--- a/chrome/browser/smart_card/smart_card_permission_request.h
+++ b/chrome/browser/smart_card/smart_card_permission_request.h
@@ -31,6 +31,7 @@
   bool IsDuplicateOf(
       permissions::PermissionRequest* other_request) const override;
   std::u16string GetMessageTextFragment() const override;
+  std::optional<std::u16string> GetAllowAlwaysText() const override;
 
   void OnPermissionDecided(ContentSetting result,
                            bool is_one_time,
diff --git a/chrome/browser/supervised_user/url_filter_interactive_uitest.cc b/chrome/browser/supervised_user/url_filter_interactive_uitest.cc
index eaaf7be..768f0cc 100644
--- a/chrome/browser/supervised_user/url_filter_interactive_uitest.cc
+++ b/chrome/browser/supervised_user/url_filter_interactive_uitest.cc
@@ -8,6 +8,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/types/strong_alias.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "chrome/test/interaction/interactive_browser_test.h"
 #include "chrome/test/supervised_user/family_live_test.h"
@@ -25,10 +26,13 @@
 
 // TODO(b/303401498): Use dedicated RPCs in supervised user e2e desktop tests
 // instead of clicking around the pages.
-class UrlFilterUiTest : public InteractiveBrowserTestT<FamilyLiveTest> {
+class UrlFilterUiTest
+    : public InteractiveBrowserTestT<FamilyLiveTest>,
+      public testing::WithParamInterface<supervised_user::FamilyIdentifier> {
  public:
   UrlFilterUiTest()
       : InteractiveBrowserTestT<FamilyLiveTest>(
+            /*family_identifier=*/GetParam(),
             /*extra_enabled_hosts=*/std::vector<std::string>(
                 {"example.com", "www.pornhub.com"})) {}
 
@@ -163,7 +167,7 @@
   }
 };
 
-IN_PROC_BROWSER_TEST_F(UrlFilterUiTest, ParentBlocksPage) {
+IN_PROC_BROWSER_TEST_P(UrlFilterUiTest, ParentBlocksPage) {
   DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kChildElementId);
   DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kParentControlsTab);
 
@@ -200,7 +204,7 @@
       WaitForStateChange(kChildElementId, RemoteApprovalButtonAppeared()));
 }
 
-IN_PROC_BROWSER_TEST_F(UrlFilterUiTest, ParentAllowsPageBlockedBySafeSites) {
+IN_PROC_BROWSER_TEST_P(UrlFilterUiTest, ParentAllowsPageBlockedBySafeSites) {
   DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kChildElementId);
   DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kParentControlsTab);
 
@@ -236,7 +240,7 @@
       WaitForStateChange(kChildElementId, PageWithMatchingTitle("Pornhub")));
 }
 
-IN_PROC_BROWSER_TEST_F(UrlFilterUiTest,
+IN_PROC_BROWSER_TEST_P(UrlFilterUiTest,
                        ParentAprovesPermissionRequestForBlockedSite) {
   DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kChildElementId);
   DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kParentControlsTab);
@@ -286,5 +290,12 @@
       WaitForStateChange(kChildElementId, PageWithMatchingTitle("Pornhub")));
 }
 
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    UrlFilterUiTest,
+    // TODO(b/315794138): Add the rest of DMA-configured accounts.
+    testing::Values(supervised_user::FamilyIdentifier("FAMILY")),
+    [](const auto& info) { return info.param->data(); });
+
 }  // namespace
 }  // namespace supervised_user
diff --git a/chrome/browser/sync/test/integration/password_manager_sync_test.cc b/chrome/browser/sync/test/integration/password_manager_sync_test.cc
index 8ec20a7..a627c6b 100644
--- a/chrome/browser/sync/test/integration/password_manager_sync_test.cc
+++ b/chrome/browser/sync/test/integration/password_manager_sync_test.cc
@@ -1133,9 +1133,6 @@
 #endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
 IN_PROC_BROWSER_TEST_F(PasswordManagerSyncTest, SyncUtilApis) {
-  // Username hardcoded in SyncTest.
-  const std::string kExpectedUsername = "user@gmail.com";
-
   ASSERT_TRUE(SetupSync());
 
   EXPECT_TRUE(
@@ -1147,7 +1144,7 @@
   EXPECT_EQ(password_manager::sync_util::
                 GetAccountEmailIfSyncFeatureEnabledIncludingPasswords(
                     GetSyncService(0)),
-            kExpectedUsername);
+            SyncTest::kDefaultUserEmail);
   EXPECT_EQ(
       password_manager::sync_util::GetPasswordSyncState(GetSyncService(0)),
       password_manager::SyncState::kSyncingNormalEncryption);
@@ -1172,7 +1169,7 @@
   EXPECT_EQ(password_manager::sync_util::
                 GetAccountEmailIfSyncFeatureEnabledIncludingPasswords(
                     GetSyncService(0)),
-            kExpectedUsername);
+            SyncTest::kDefaultUserEmail);
 }
 
 #if !BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc b/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc
index dbb40d5..f4b478f8 100644
--- a/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc
@@ -94,11 +94,6 @@
 using testing::NotNull;
 using testing::SizeIs;
 
-const char kGaiaId[] = "gaia_id_for_user_gmail.com";
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
-const char kAccountEmail[] = "user@gmail.com";
-#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
-
 MATCHER_P(IsDataEncryptedWith, key_params, "") {
   const sync_pb::EncryptedData& encrypted_data = arg;
   std::unique_ptr<syncer::Nigori> nigori = syncer::Nigori::CreateByDerivation(
@@ -131,6 +126,10 @@
   return true;
 }
 
+std::string GetDefaultUserGaiaID() {
+  return signin::GetTestGaiaIdForEmail(SyncTest::kDefaultUserEmail);
+}
+
 std::string ComputeKeyName(const KeyParamsForTesting& key_params) {
   return syncer::Nigori::CreateByDerivation(key_params.derivation_params,
                                             key_params.password)
@@ -908,7 +907,7 @@
         base::Unretained(security_domains_server_.get())));
 
     encryption_helper::SetupFakeTrustedVaultPages(
-        kGaiaId, kTestEncryptionKey, kTestEncryptionKeyVersion,
+        GetDefaultUserGaiaID(), kTestEncryptionKey, kTestEncryptionKeyVersion,
         kTestRecoveryMethodPublicKey, embedded_test_server());
 
     embedded_test_server()->StartAcceptingConnections();
@@ -1185,7 +1184,8 @@
                         GetFakeServer());
   ASSERT_TRUE(SetupClients());
   GetSyncTrustedVaultClient()->StoreKeys(
-      kGaiaId, GetSecurityDomainsServer()->GetAllTrustedVaultKeys(),
+      GetDefaultUserGaiaID(),
+      GetSecurityDomainsServer()->GetAllTrustedVaultKeys(),
       /*last_key_version=*/GetSecurityDomainsServer()->GetCurrentEpoch());
 
   NotificationDisplayServiceTester display_service(GetProfile(0));
@@ -1642,7 +1642,8 @@
       GetFakeServer());
   ASSERT_TRUE(SetupClients());
   GetSyncTrustedVaultClient()->StoreKeys(
-      kGaiaId, GetSecurityDomainsServer()->GetAllTrustedVaultKeys(),
+      GetDefaultUserGaiaID(),
+      GetSecurityDomainsServer()->GetAllTrustedVaultKeys(),
       /*last_key_version=*/GetSecurityDomainsServer()->GetCurrentEpoch());
   ASSERT_TRUE(SetupSync());
 
@@ -1738,14 +1739,15 @@
   GetSecurityDomainsServer()->RequirePublicKeyToAvoidRecoverabilityDegraded(
       kTestRecoveryMethodPublicKey);
   GetSyncTrustedVaultClient()->StoreKeys(
-      kGaiaId, GetSecurityDomainsServer()->GetAllTrustedVaultKeys(),
+      GetDefaultUserGaiaID(),
+      GetSecurityDomainsServer()->GetAllTrustedVaultKeys(),
       /*last_key_version=*/GetSecurityDomainsServer()->GetCurrentEpoch());
 
   // Mimic a recovery method being added before or during sign-in, which should
   // be deferred until sign-in completes.
   base::RunLoop run_loop;
   GetSyncTrustedVaultClient()->AddTrustedRecoveryMethod(
-      kGaiaId, kTestRecoveryMethodPublicKey, kTestMethodTypeHint,
+      GetDefaultUserGaiaID(), kTestRecoveryMethodPublicKey, kTestMethodTypeHint,
       run_loop.QuitClosure());
 
   ASSERT_TRUE(GetSecurityDomainsServer()->IsRecoverabilityDegraded());
@@ -1781,7 +1783,8 @@
   GetSecurityDomainsServer()->RequirePublicKeyToAvoidRecoverabilityDegraded(
       kTestRecoveryMethodPublicKey);
   GetSyncTrustedVaultClient()->StoreKeys(
-      kGaiaId, GetSecurityDomainsServer()->GetAllTrustedVaultKeys(),
+      GetDefaultUserGaiaID(),
+      GetSecurityDomainsServer()->GetAllTrustedVaultKeys(),
       /*last_key_version=*/GetSecurityDomainsServer()->GetCurrentEpoch());
   ASSERT_TRUE(GetSecurityDomainsServer()->IsRecoverabilityDegraded());
 
@@ -1796,7 +1799,7 @@
   // should be deferred until the auth error is resolved.
   base::RunLoop run_loop;
   GetSyncTrustedVaultClient()->AddTrustedRecoveryMethod(
-      kGaiaId, kTestRecoveryMethodPublicKey, kTestMethodTypeHint,
+      GetDefaultUserGaiaID(), kTestRecoveryMethodPublicKey, kTestMethodTypeHint,
       run_loop.QuitClosure());
 
   // Mimic the auth error state being resolved.
@@ -1826,7 +1829,8 @@
                         GetFakeServer());
   ASSERT_TRUE(SetupClients());
   GetSyncTrustedVaultClient()->StoreKeys(
-      kGaiaId, GetSecurityDomainsServer()->GetAllTrustedVaultKeys(),
+      GetDefaultUserGaiaID(),
+      GetSecurityDomainsServer()->GetAllTrustedVaultKeys(),
       /*last_key_version=*/GetSecurityDomainsServer()->GetCurrentEpoch());
   ASSERT_TRUE(SetupSync());
   ASSERT_FALSE(GetSecurityDomainsServer()->IsRecoverabilityDegraded());
@@ -1957,7 +1961,7 @@
   // Mimic a recovery method being added.
   base::RunLoop run_loop;
   GetSyncTrustedVaultClient()->AddTrustedRecoveryMethod(
-      kGaiaId, kTestRecoveryMethodPublicKey, kTestMethodTypeHint,
+      GetDefaultUserGaiaID(), kTestRecoveryMethodPublicKey, kTestMethodTypeHint,
       run_loop.QuitClosure());
   run_loop.Run();
 
@@ -2058,7 +2062,7 @@
   // SetupClients() must have been already called.
   void SetupSyncTransport() {
     secondary_account_helper::SignInUnconsentedAccount(
-        GetProfile(0), &test_url_loader_factory_, kAccountEmail);
+        GetProfile(0), &test_url_loader_factory_, SyncTest::kDefaultUserEmail);
     ASSERT_TRUE(GetClient(0)->AwaitSyncTransportActive());
     ASSERT_FALSE(GetSyncService(0)->IsSyncFeatureEnabled());
   }
@@ -2131,7 +2135,8 @@
                         GetFakeServer());
   ASSERT_TRUE(SetupClients());
   GetSyncTrustedVaultClient()->StoreKeys(
-      kGaiaId, GetSecurityDomainsServer()->GetAllTrustedVaultKeys(),
+      GetDefaultUserGaiaID(),
+      GetSecurityDomainsServer()->GetAllTrustedVaultKeys(),
       /*last_key_version=*/GetSecurityDomainsServer()->GetCurrentEpoch());
 
   SetupSyncTransport();
diff --git a/chrome/browser/sync/test/integration/single_client_user_consents_sync_test.cc b/chrome/browser/sync/test/integration/single_client_user_consents_sync_test.cc
index 009c383..35ed0c91 100644
--- a/chrome/browser/sync/test/integration/single_client_user_consents_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_user_consents_sync_test.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/sync/test/integration/sync_service_impl_harness.h"
 #include "chrome/browser/sync/test/integration/sync_test.h"
 #include "components/consent_auditor/consent_auditor.h"
+#include "components/signin/public/identity_manager/identity_test_utils.h"
 #include "components/sync/protocol/user_consent_specifics.pb.h"
 #include "content/public/test/browser_test.h"
 
@@ -25,7 +26,8 @@
 namespace {
 
 CoreAccountId GetAccountId() {
-  return CoreAccountId::FromGaiaId("gaia_id_for_user_gmail.com");
+  return CoreAccountId::FromGaiaId(
+      signin::GetTestGaiaIdForEmail(SyncTest::kDefaultUserEmail));
 }
 
 class UserConsentEqualityChecker : public SingleClientStatusChangeChecker {
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc
index 1a3818e..a13a6c13 100644
--- a/chrome/browser/sync/test/integration/sync_test.cc
+++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -224,7 +224,7 @@
     if (cl->HasSwitch(switches::kSyncUserForTest)) {
       username_ = cl->GetSwitchValueASCII(switches::kSyncUserForTest);
     } else if (server_type_ != EXTERNAL_LIVE_SERVER) {
-      username_ = "user@gmail.com";
+      username_ = kDefaultUserEmail;
     }
     // Decide on password to use.
     password_ = cl->HasSwitch(switches::kSyncPasswordForTest)
diff --git a/chrome/browser/sync/test/integration/sync_test.h b/chrome/browser/sync/test/integration/sync_test.h
index 7fe15e0..4b1ad0f 100644
--- a/chrome/browser/sync/test/integration/sync_test.h
+++ b/chrome/browser/sync/test/integration/sync_test.h
@@ -141,6 +141,9 @@
     WAIT_FOR_COMMITS_TO_COMPLETE,
   };
 
+  // Used unless specified otherwise by command line switches.
+  static constexpr char kDefaultUserEmail[] = "user@gmail.com";
+
   // A SyncTest must be associated with a particular test type.
   explicit SyncTest(TestType test_type);
 
diff --git a/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc b/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc
index f67625c8..a46bd4b 100644
--- a/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc
@@ -14,7 +14,7 @@
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/profile_token_quality.h"
 #include "components/autofill/core/browser/profile_token_quality_test_api.h"
-#include "components/autofill/core/browser/webdata/autofill_table.h"
+#include "components/autofill/core/browser/webdata/autofill_table_utils.h"
 #include "components/autofill/core/common/autofill_features.h"
 #include "components/sync/engine/cycle/entity_change_metric_recording.h"
 #include "content/public/test/browser_test.h"
@@ -23,7 +23,6 @@
 namespace {
 
 using autofill::AutofillProfile;
-using autofill::AutofillTable;
 using autofill::AutofillType;
 using autofill::CreditCard;
 using autofill::PersonalDataManager;
@@ -395,7 +394,7 @@
   AddProfile(0, CreateAutofillProfile(PROFILE_HOMER));
   ASSERT_TRUE(AutofillProfileChecker(0, 1, /*expected_count=*/1U).Wait());
 
-  std::u16string max_length_string(AutofillTable::kMaxDataLength, '.');
+  std::u16string max_length_string(autofill::kMaxDataLengthForDatabase, '.');
   UpdateProfile(0, GetAllAutoFillProfiles(0)[0]->guid(),
                 AutofillType(autofill::NAME_FULL), max_length_string);
   UpdateProfile(0, GetAllAutoFillProfiles(0)[0]->guid(),
@@ -406,7 +405,7 @@
   EXPECT_TRUE(AutofillProfileChecker(0, 1, /*expected_count=*/1U).Wait());
 }
 
-// Tests that values exceeding `AutofillTable::kMaxDataLength` are truncated.
+// Tests that values exceeding `kMaxDataLengthForDatabase` are truncated.
 // TODO(crbug.com/1443393): As of the unified table layout, values are already
 // truncated in AutofillTable. No special logic on the Sync-side is necessary.
 // Clean this up.
@@ -416,8 +415,8 @@
   AddProfile(0, CreateAutofillProfile(PROFILE_HOMER));
   ASSERT_TRUE(AutofillProfileChecker(0, 1, /*expected_count=*/1U).Wait());
 
-  std::u16string exceeds_max_length_string(AutofillTable::kMaxDataLength + 1,
-                                           '.');
+  std::u16string exceeds_max_length_string(
+      autofill::kMaxDataLengthForDatabase + 1, '.');
   UpdateProfile(0, GetAllAutoFillProfiles(0)[0]->guid(),
                 AutofillType(autofill::NAME_FIRST), exceeds_max_length_string);
   UpdateProfile(0, GetAllAutoFillProfiles(0)[0]->guid(),
@@ -433,7 +432,8 @@
   for (const auto type :
        {autofill::NAME_FIRST, autofill::NAME_LAST, autofill::EMAIL_ADDRESS,
         autofill::ADDRESS_HOME_LINE1}) {
-    EXPECT_EQ(profile->GetRawInfo(type).size(), AutofillTable::kMaxDataLength);
+    EXPECT_EQ(profile->GetRawInfo(type).size(),
+              autofill::kMaxDataLengthForDatabase);
   }
 
   ASSERT_TRUE(AwaitQuiescence());
diff --git a/chrome/browser/tab_contents/navigation_metrics_recorder.cc b/chrome/browser/tab_contents/navigation_metrics_recorder.cc
index e0735f0..7ea423c 100644
--- a/chrome/browser/tab_contents/navigation_metrics_recorder.cc
+++ b/chrome/browser/tab_contents/navigation_metrics_recorder.cc
@@ -123,12 +123,6 @@
         site_engagement_service_->GetEngagementLevel(url);
     base::UmaHistogramEnumeration("Navigation.MainFrame.SiteEngagementLevel",
                                   engagement_level);
-
-    if (navigation_handle->IsFormSubmission()) {
-      base::UmaHistogramEnumeration(
-          "Navigation.MainFrameFormSubmission.SiteEngagementLevel",
-          engagement_level);
-    }
   }
   if (url.SchemeIsHTTPOrHTTPS() && !navigation_handle->IsDownload()) {
     ThirdPartyCookieBlockState block_state = GetThirdPartyCookieBlockState(url);
diff --git a/chrome/browser/tab_contents/navigation_metrics_recorder_browsertest.cc b/chrome/browser/tab_contents/navigation_metrics_recorder_browsertest.cc
index 7eae7efd..e86d0ad0 100644
--- a/chrome/browser/tab_contents/navigation_metrics_recorder_browsertest.cc
+++ b/chrome/browser/tab_contents/navigation_metrics_recorder_browsertest.cc
@@ -89,33 +89,6 @@
                                blink::mojom::EngagementLevel::HIGH, 1);
 }
 
-IN_PROC_BROWSER_TEST_F(NavigationMetricsRecorderBrowserTest,
-                       FormSubmission_EngagementLevel) {
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-
-  ASSERT_TRUE(embedded_test_server()->Start());
-  const GURL url(embedded_test_server()->GetURL("/form.html"));
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
-
-  // Submit a form and check the histograms. Before doing so, we set a high site
-  // engagement score so that a single form submission doesn't affect the score
-  // much.
-  site_engagement::SiteEngagementService::Get(browser()->profile())
-      ->ResetBaseScoreForURL(url, kHighEngagementScore);
-  base::HistogramTester histograms;
-  content::TestNavigationObserver observer(web_contents);
-  const char* const kScript = "document.getElementById('form').submit()";
-  EXPECT_TRUE(content::ExecJs(web_contents, kScript));
-  observer.WaitForNavigationFinished();
-
-  histograms.ExpectTotalCount(
-      "Navigation.MainFrameFormSubmission.SiteEngagementLevel", 1);
-  histograms.ExpectBucketCount(
-      "Navigation.MainFrameFormSubmission.SiteEngagementLevel",
-      blink::mojom::EngagementLevel::HIGH, 1);
-}
-
 class NavigationMetricsRecorderPrerenderBrowserTest
     : public NavigationMetricsRecorderBrowserTest {
  public:
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 7d84fe8..50418a2 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1768,6 +1768,8 @@
       "webui/privacy_sandbox/privacy_sandbox_dialog_handler.h",
       "webui/privacy_sandbox/privacy_sandbox_dialog_ui.cc",
       "webui/privacy_sandbox/privacy_sandbox_dialog_ui.h",
+      "webui/privacy_sandbox/privacy_sandbox_internals_handler.cc",
+      "webui/privacy_sandbox/privacy_sandbox_internals_handler.h",
       "webui/profile_info_watcher.cc",
       "webui/profile_info_watcher.h",
       "webui/profile_internals/profile_internals_handler.cc",
@@ -2008,6 +2010,7 @@
       "//chrome/browser/new_tab_page/modules/v2/history_clusters:mojo_bindings",
       "//chrome/browser/new_tab_page/modules/v2/tab_resumption:mojo_bindings",
       "//chrome/browser/profile_resetter:profile_reset_report_proto",
+      "//chrome/browser/push_notification:push_notification",
       "//chrome/browser/safe_browsing",
       "//chrome/browser/safe_browsing:advanced_protection",
       "//chrome/browser/support_tool:support_tool_proto",
@@ -2023,6 +2026,7 @@
       "//chrome/browser/ui/webui/new_tab_page:mojo_bindings",
       "//chrome/browser/ui/webui/new_tab_page_third_party:mojo_bindings",
       "//chrome/browser/ui/webui/on_device_internals:mojom",
+      "//chrome/browser/ui/webui/privacy_sandbox:mojo_bindings",
       "//chrome/browser/ui/webui/search_engine_choice:mojo_bindings",
       "//chrome/browser/ui/webui/side_panel/bookmarks:mojo_bindings",
       "//chrome/browser/ui/webui/side_panel/customize_chrome:mojo_bindings",
@@ -2061,6 +2065,7 @@
       "//components/password_manager/content/common",
       "//components/performance_manager:site_data_proto",
       "//components/power_bookmarks/core:features",
+      "//components/push_notification:push_notification",
       "//components/reading_list/features:flags",
       "//components/safe_browsing/core/common:safe_browsing_policy_handler",
       "//components/safety_check",
@@ -3557,8 +3562,6 @@
       "webui/help/version_updater_chromeos.h",
       "webui/management/management_ui_handler_chromeos.cc",
       "webui/management/management_ui_handler_chromeos.h",
-      "webui/nearby_internals/nearby_internals_chime_handler.cc",
-      "webui/nearby_internals/nearby_internals_chime_handler.h",
       "webui/nearby_internals/nearby_internals_contact_handler.cc",
       "webui/nearby_internals/nearby_internals_contact_handler.h",
       "webui/nearby_internals/nearby_internals_http_handler.cc",
@@ -3567,6 +3570,8 @@
       "webui/nearby_internals/nearby_internals_logs_handler.h",
       "webui/nearby_internals/nearby_internals_prefs_handler.cc",
       "webui/nearby_internals/nearby_internals_prefs_handler.h",
+      "webui/nearby_internals/nearby_internals_push_notification_handler.cc",
+      "webui/nearby_internals/nearby_internals_push_notification_handler.h",
       "webui/nearby_internals/nearby_internals_ui.cc",
       "webui/nearby_internals/nearby_internals_ui.h",
       "webui/nearby_internals/nearby_internals_ui_presence_handler.cc",
diff --git a/chrome/browser/ui/android/page_insights/java/src/org/chromium/chrome/browser/page_insights/PageInsightsCoordinator.java b/chrome/browser/ui/android/page_insights/java/src/org/chromium/chrome/browser/page_insights/PageInsightsCoordinator.java
index c83c7cac..de2160b 100644
--- a/chrome/browser/ui/android/page_insights/java/src/org/chromium/chrome/browser/page_insights/PageInsightsCoordinator.java
+++ b/chrome/browser/ui/android/page_insights/java/src/org/chromium/chrome/browser/page_insights/PageInsightsCoordinator.java
@@ -23,6 +23,7 @@
 import org.chromium.components.browser_ui.bottomsheet.ExpandedSheetHelper;
 import org.chromium.components.browser_ui.bottomsheet.ManagedBottomSheetController;
 import org.chromium.content_public.browser.NavigationHandle;
+import org.chromium.ui.base.ApplicationViewportInsetSupplier;
 
 import java.util.function.BooleanSupplier;
 import java.util.function.Function;
@@ -64,6 +65,7 @@
      * @param browserControlsSizer Bottom browser controls resizer.
      * @param backPressManager Back press manager.
      * @param inMotionSupplier Supplier for whether the compositor is in motion.
+     * @param appViewportInsetSupplier App-wide viewport inset supplier.
      * @param isPageInsightsHubEnabled Supplier of the feature flag.
      * @param firstLoadTimeMs Timestamp for the first page load completion.
      */
@@ -80,6 +82,7 @@
             BrowserControlsSizer browserControlsSizer,
             @Nullable BackPressManager backPressManager,
             @Nullable ObservableSupplier<Boolean> inMotionSupplier,
+            ApplicationViewportInsetSupplier appViewportInsetSupplier,
             BooleanSupplier isPageInsightsEnabledSupplier,
             Function<NavigationHandle, PageInsightsConfig> pageInsightsConfigProvider) {
         mContext = context;
@@ -103,6 +106,7 @@
                         mBrowserControlsSizer,
                         backPressManager,
                         inMotionSupplier,
+                        appViewportInsetSupplier,
                         isPageInsightsEnabledSupplier,
                         pageInsightsConfigProvider);
     }
diff --git a/chrome/browser/ui/android/page_insights/java/src/org/chromium/chrome/browser/page_insights/PageInsightsCoordinatorTest.java b/chrome/browser/ui/android/page_insights/java/src/org/chromium/chrome/browser/page_insights/PageInsightsCoordinatorTest.java
index f5d4786c..446510d1 100644
--- a/chrome/browser/ui/android/page_insights/java/src/org/chromium/chrome/browser/page_insights/PageInsightsCoordinatorTest.java
+++ b/chrome/browser/ui/android/page_insights/java/src/org/chromium/chrome/browser/page_insights/PageInsightsCoordinatorTest.java
@@ -83,6 +83,7 @@
 import org.chromium.content_public.browser.NavigationHandle;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.ui.KeyboardVisibilityDelegate;
+import org.chromium.ui.base.ApplicationViewportInsetSupplier;
 import org.chromium.ui.test.util.BlankUiTestActivity;
 import org.chromium.url.GURL;
 import org.chromium.url.JUnitTestGURLs;
@@ -132,6 +133,7 @@
     @Mock private BackPressManager mBackPressManager;
     @Mock private ObservableSupplierImpl<Boolean> mInMotionSupplier;
     @Mock private NavigationHandle mNavigationHandle;
+    @Mock private ApplicationViewportInsetSupplier mAppInsetSupplier;
 
     private PageInsightsCoordinator mPageInsightsCoordinator;
     private ManagedBottomSheetController mPageInsightsController;
@@ -240,6 +242,7 @@
                                         mBrowserControlsSizer,
                                         mBackPressManager,
                                         mInMotionSupplier,
+                                        mAppInsetSupplier,
                                         mIsPageInsightsHubEnabled,
                                         (navigationHandle) ->
                                                 PageInsightsConfig.newBuilder()
diff --git a/chrome/browser/ui/android/page_insights/java/src/org/chromium/chrome/browser/page_insights/PageInsightsMediator.java b/chrome/browser/ui/android/page_insights/java/src/org/chromium/chrome/browser/page_insights/PageInsightsMediator.java
index 41e39e2..0a90028 100644
--- a/chrome/browser/ui/android/page_insights/java/src/org/chromium/chrome/browser/page_insights/PageInsightsMediator.java
+++ b/chrome/browser/ui/android/page_insights/java/src/org/chromium/chrome/browser/page_insights/PageInsightsMediator.java
@@ -57,6 +57,7 @@
 import org.chromium.components.embedder_support.util.UrlConstants;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.NavigationHandle;
+import org.chromium.ui.base.ApplicationViewportInsetSupplier;
 import org.chromium.ui.util.ColorUtils;
 import org.chromium.url.GURL;
 
@@ -141,6 +142,8 @@
     @Nullable private final ObservableSupplier<Boolean> mInMotionSupplier;
     @Nullable private final BackPressManager mBackPressManager;
     @Nullable private final BackPressHandler mBackPressHandler;
+    private final ObservableSupplierImpl<Integer> mSheetInset = new ObservableSupplierImpl<>();
+    private final boolean mResizeInSync;
 
     private PageInsightsDataLoader mPageInsightsDataLoader;
     @Nullable private PageInsightsSurfaceRenderer mSurfaceRenderer;
@@ -233,6 +236,7 @@
             BrowserControlsSizer browserControlsSizer,
             @Nullable BackPressManager backPressManager,
             @Nullable ObservableSupplier<Boolean> inMotionSupplier,
+            ApplicationViewportInsetSupplier appViewportInsetSupplier,
             BooleanSupplier isPageInsightsEnabledSupplier,
             Function<NavigationHandle, PageInsightsConfig> pageInsightsConfigProvider) {
         mContext = context;
@@ -328,6 +332,10 @@
         } else {
             mBackPressHandler = null;
         }
+
+        // Native is ready by now. The feature flag can be cached from here.
+        mResizeInSync = ChromeFeatureList.sPageInsightsResizeInSync.isEnabled();
+        if (mResizeInSync) appViewportInsetSupplier.setBottomSheetInsetSupplier(mSheetInset);
     }
 
     void initView(View bottomSheetContainer) {
@@ -403,6 +411,8 @@
         mHandler.removeCallbacks(mAutoTriggerTimerRunnable);
     }
 
+    // TabObserver
+
     @Override
     public void onPageLoadStarted(Tab tab, GURL url) {
         Log.v(TAG, "onPageLoadStarted");
@@ -638,10 +648,12 @@
     public void onSheetStateChanged(@SheetState int newState, @StateChangeReason int reason) {
         if (newState == SheetState.HIDDEN) {
             mWillHandleBackPressSupplier.set(false);
+            if (mResizeInSync) mSheetInset.set(0);
             setBottomControlsHeight(mSheetController.getCurrentOffset());
             handleDismissal(mOldState);
         } else if (newState == SheetState.PEEK) {
             mWillHandleBackPressSupplier.set(false);
+            if (mResizeInSync) mSheetInset.set(0);
             setBottomControlsHeight(mSheetController.getCurrentOffset());
             setBackgroundColors(/* ratioOfCompletionFromPeekToExpanded= */ .0f);
             // The user should always be able to swipe to dismiss from peek state.
@@ -715,11 +727,21 @@
     @Override
     public void onSheetOffsetChanged(float heightFraction, float offsetPx) {
         float peekHeightRatio = getPeekHeightRatio();
-        if (mSheetController.getSheetState() == SheetState.SCROLLING
-                && heightFraction < peekHeightRatio) {
-            // Set the content height to zero in advance when user drags/scrolls the sheet down
-            // below the peeking state. This helps hide the white patch (blank bottom controls).
-            setBottomControlsHeight(0);
+        if (mSheetController.getSheetState() == SheetState.SCROLLING) {
+            if (mResizeInSync) {
+                // Calling |setBottomControlsHeight| to resize WebContents per each offset change
+                // is janky. While the sheet is being dragged, let the app-wide inset supplier
+                // handle the resizing so the sheet and the contents move in sync smoothly.
+                if (BrowserControlsUtils.areBrowserControlsFullyVisible(mControlsStateProvider)
+                        && heightFraction < peekHeightRatio) {
+                    setBottomControlsHeight(0);
+                    mSheetInset.set((int) offsetPx);
+                }
+            } else if (heightFraction < peekHeightRatio) {
+                // Set the content height to zero in advance when user drags/scrolls the sheet down
+                // below the peeking state. This helps hide the white patch (blank bottom controls).
+                setBottomControlsHeight(0);
+            }
         }
 
         float ratioOfCompletionFromPeekToExpanded =
@@ -795,6 +817,10 @@
         return mSheetContainer;
     }
 
+    ObservableSupplierImpl<Integer> getSheetInsetForTesting() {
+        return mSheetInset;
+    }
+
     private PageInsightsSurfaceRenderer getSurfaceRenderer() {
         if (mSurfaceRenderer != null) {
             return mSurfaceRenderer;
diff --git a/chrome/browser/ui/android/page_insights/java/src/org/chromium/chrome/browser/page_insights/PageInsightsMediatorTest.java b/chrome/browser/ui/android/page_insights/java/src/org/chromium/chrome/browser/page_insights/PageInsightsMediatorTest.java
index 53767d8..8f82a05 100644
--- a/chrome/browser/ui/android/page_insights/java/src/org/chromium/chrome/browser/page_insights/PageInsightsMediatorTest.java
+++ b/chrome/browser/ui/android/page_insights/java/src/org/chromium/chrome/browser/page_insights/PageInsightsMediatorTest.java
@@ -11,10 +11,13 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -58,6 +61,7 @@
 import org.chromium.base.FeatureList;
 import org.chromium.base.FeatureList.TestValues;
 import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.supplier.Supplier;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.HistogramWatcher;
@@ -104,6 +108,7 @@
 import org.chromium.components.signin.identitymanager.IdentityManager;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.NavigationHandle;
+import org.chromium.ui.base.ApplicationViewportInsetSupplier;
 import org.chromium.url.GURL;
 import org.chromium.url.JUnitTestGURLs;
 
@@ -149,6 +154,7 @@
     @Mock private Function<NavigationHandle, PageInsightsConfig> mPageInsightsConfigProvider;
     @Mock private NavigationHandle mNavigationHandle;
     @Mock private ObservableSupplier<Boolean> mInMotionSupplier;
+    @Mock private ApplicationViewportInsetSupplier mAppInsetSupplier;
 
     @Captor
     private ArgumentCaptor<BrowserControlsStateProvider.Observer>
@@ -222,7 +228,7 @@
     }
 
     private void createMediator(TestValues testValues) {
-        FeatureList.setTestValues(testValues);
+        FeatureList.mergeTestValues(testValues, /* replace= */ true);
         Context context = ContextUtils.getApplicationContext();
         context.setTheme(org.chromium.chrome.R.style.Theme_BrowserUI);
         mMediator =
@@ -239,6 +245,7 @@
                         mBrowserControlsSizer,
                         mBackPressManager,
                         mInMotionSupplier,
+                        mAppInsetSupplier,
                         () -> true,
                         mPageInsightsConfigProvider);
         verify(mControlsStateProvider).addObserver(mBrowserControlsStateProviderObserver.capture());
@@ -1174,6 +1181,63 @@
                 .hideContent(eq(mMediator.getSheetContent()), anyBoolean());
     }
 
+    @Test
+    @MediumTest
+    public void resizeInSync() {
+        TestValues testValues = new TestValues();
+        testValues.addFeatureFlagOverride(
+                ChromeFeatureList.CCT_PAGE_INSIGHTS_HUB_BETTER_SCROLL, true);
+        FeatureList.mergeTestValues(testValues, /* replace= */ true);
+        createMediator();
+        ObservableSupplierImpl<Integer> sheetInset = mMediator.getSheetInsetForTesting();
+        verify(mAppInsetSupplier).setBottomSheetInsetSupplier(sheetInset);
+
+        int fullHeight = 2000;
+        ViewGroup contentView = (ViewGroup) mock(ViewGroup.class);
+        when(contentView.getMeasuredHeight()).thenReturn(fullHeight);
+        var sheetContent = mMediator.getSheetContent();
+        sheetContent.setShouldHavePeekStateForTesting(true);
+        sheetContent.setContentViewForTesting(contentView);
+        sheetContent.setFullScreenHeightForTesting(fullHeight);
+        int peekSheetHeight = sheetContent.getPeekHeight();
+
+        // First, let the sheet move to peeking state.
+        when(mBottomSheetController.getCurrentOffset()).thenReturn(peekSheetHeight);
+        when(mBottomSheetController.getSheetState()).thenReturn(SheetState.PEEK);
+
+        sheetInset.set(1); // set a non-zero value for testing.
+        mMediator.onSheetStateChanged(SheetState.PEEK, StateChangeReason.SWIPE);
+
+        verify(mBrowserControlsSizer).setBottomControlsHeight(eq(peekSheetHeight), eq(0));
+        assertEquals("BottomSheet inset should be reset", 0, (int) sheetInset.get());
+        clearInvocations(mBrowserControlsSizer);
+
+        // Make the browser controls fully visible.
+        when(mControlsStateProvider.getBrowserControlHiddenRatio()).thenReturn(0.f);
+        when(mBottomSheetController.getSheetState()).thenReturn(SheetState.SCROLLING);
+
+        // Simulate drag up and down the sheet across the peeking height.
+        float fraction = peekSheetHeight / (float) fullHeight + 0.1f; // above peek height
+        int offset = (int) (fullHeight * fraction);
+        mMediator.onSheetOffsetChanged(fraction, offset);
+        verify(mBrowserControlsSizer, never()).setBottomControlsHeight(anyInt(), anyInt());
+        assertEquals("BottomSheet inset should remain zero", 0, (int) sheetInset.get());
+
+        fraction = peekSheetHeight / (float) fullHeight - 0.1f; // below peek height
+        offset = (int) (fullHeight * fraction);
+        mMediator.onSheetOffsetChanged(fraction, offset);
+        verify(mBrowserControlsSizer, never()).setBottomControlsHeight(eq(offset), eq(0));
+        assertEquals("BottomSheet inset should be updated", offset, (int) sheetInset.get());
+
+        // Hide the sheet.
+        when(mBottomSheetController.getCurrentOffset()).thenReturn(0);
+        when(mBottomSheetController.getSheetState()).thenReturn(SheetState.HIDDEN);
+        mMediator.onSheetStateChanged(SheetState.HIDDEN, StateChangeReason.SWIPE);
+
+        verify(mBrowserControlsSizer).setBottomControlsHeight(eq(0), eq(0));
+        assertEquals("BottomSheet inset should be reset", 0, (int) sheetInset.get());
+    }
+
     private PageInsightsMetadata getPageInsightsMetadata() {
         Page childPage =
                 Page.newBuilder()
diff --git a/chrome/browser/ui/android/page_insights/java/src/org/chromium/chrome/browser/page_insights/PageInsightsSheetContent.java b/chrome/browser/ui/android/page_insights/java/src/org/chromium/chrome/browser/page_insights/PageInsightsSheetContent.java
index 3a89cbf..d4949c3dc 100644
--- a/chrome/browser/ui/android/page_insights/java/src/org/chromium/chrome/browser/page_insights/PageInsightsSheetContent.java
+++ b/chrome/browser/ui/android/page_insights/java/src/org/chromium/chrome/browser/page_insights/PageInsightsSheetContent.java
@@ -521,4 +521,16 @@
         }
         return null;
     }
+
+    void setContentViewForTesting(ViewGroup view) {
+        mSheetContentView = view;
+    }
+
+    void setShouldHavePeekStateForTesting(boolean hasPeek) {
+        mShouldHavePeekState = hasPeek;
+    }
+
+    void setFullScreenHeightForTesting(int height) {
+        mFullScreenHeight = height;
+    }
 }
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index 2ee7cf9..daa6964 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -2577,9 +2577,6 @@
       <message name="IDS_WEBAPK_INSTALL_FAILED_ACTION_OPEN" desc="The label of the button which upon click would open the site user was trying to install as PWA. ">
         Go back to site
       </message>
-      <message name="IDS_WEBAPK_INSTALL_FAILED_ACTION_RETRY" desc="The label of the button which upon click would retry installing the PWA">
-        Try again
-      </message>
       <message name="IDS_IPH_PWA_INSTALL_AVAILABLE_TEXT" desc="The in-product-help message for PWAs that can be installed to the device.">
         Install this app
       </message>
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_WEBAPK_INSTALL_FAILED_ACTION_RETRY.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_WEBAPK_INSTALL_FAILED_ACTION_RETRY.png.sha1
deleted file mode 100644
index 17a691a..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_WEBAPK_INSTALL_FAILED_ACTION_RETRY.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-0ea37341edabe238d812fc27acd3d185f44b6518
\ No newline at end of file
diff --git a/chrome/browser/ui/android/toolbar/BUILD.gn b/chrome/browser/ui/android/toolbar/BUILD.gn
index baf44703..faeeacd 100644
--- a/chrome/browser/ui/android/toolbar/BUILD.gn
+++ b/chrome/browser/ui/android/toolbar/BUILD.gn
@@ -303,6 +303,7 @@
   sources = [
     "java/src/org/chromium/chrome/browser/toolbar/BaseButtonDataProviderTest.java",
     "java/src/org/chromium/chrome/browser/toolbar/ConstraintsCheckerTest.java",
+    "java/src/org/chromium/chrome/browser/toolbar/LocationBarFocusScrimHandlerTest.java",
     "java/src/org/chromium/chrome/browser/toolbar/ToolbarProgressBarTest.java",
     "java/src/org/chromium/chrome/browser/toolbar/VoiceToolbarButtonControllerUnitTest.java",
     "java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveButtonActionMenuCoordinatorTest.java",
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/LocationBarFocusScrimHandler.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/LocationBarFocusScrimHandler.java
index f63ddcb..4e28029 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/LocationBarFocusScrimHandler.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/LocationBarFocusScrimHandler.java
@@ -5,10 +5,10 @@
 package org.chromium.chrome.browser.toolbar;
 
 import android.content.Context;
-import android.content.res.Resources;
 import android.view.View;
 
 import org.chromium.base.Callback;
+import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.chrome.browser.omnibox.LocationBarDataProvider;
 import org.chromium.chrome.browser.omnibox.UrlFocusChangeListener;
 import org.chromium.components.browser_ui.widget.scrim.ScrimCoordinator;
@@ -33,16 +33,18 @@
     private final LocationBarDataProvider mLocationBarDataProvider;
     private final Runnable mClickDelegate;
     private final Context mContext;
+    private ObservableSupplier<Integer> mTabStripHeightSupplier;
+    private Callback<Integer> mTabStripHeightChangeCallback;
 
     /**
-     *
      * @param scrimCoordinator Coordinator responsible for showing and hiding the scrim view.
      * @param visibilityChangeCallback Callback used to obscure/unobscure tabs when the scrim is
-     *         shown/hidden.
+     *     shown/hidden.
      * @param context Context for retrieving resources.
      * @param locationBarDataProvider Provider of location bar data, e.g. the NTP state.
-     * @param clickDelegate Click handler for the scrim
+     * @param clickDelegate Click handler for the scrim.
      * @param scrimTarget View that the scrim should be anchored to.
+     * @param tabStripHeightSupplier Supplier for the tab strip height.
      */
     public LocationBarFocusScrimHandler(
             ScrimCoordinator scrimCoordinator,
@@ -50,14 +52,14 @@
             Context context,
             LocationBarDataProvider locationBarDataProvider,
             Runnable clickDelegate,
-            View scrimTarget) {
+            View scrimTarget,
+            ObservableSupplier<Integer> tabStripHeightSupplier) {
         mScrimCoordinator = scrimCoordinator;
         mLocationBarDataProvider = locationBarDataProvider;
         mClickDelegate = clickDelegate;
         mContext = context;
 
-        Resources resources = context.getResources();
-        int topMargin = resources.getDimensionPixelSize(R.dimen.tab_strip_height);
+        int topMargin = tabStripHeightSupplier.get() == null ? 0 : tabStripHeightSupplier.get();
         mLightScrimColor = context.getColor(R.color.omnibox_focused_fading_background_color_light);
         mScrimModel =
                 new PropertyModel.Builder(ScrimProperties.ALL_KEYS)
@@ -69,6 +71,11 @@
                         .with(ScrimProperties.VISIBILITY_CALLBACK, visibilityChangeCallback)
                         .with(ScrimProperties.BACKGROUND_COLOR, ScrimProperties.INVALID_COLOR)
                         .build();
+
+        mTabStripHeightSupplier = tabStripHeightSupplier;
+        mTabStripHeightChangeCallback =
+                newHeight -> mScrimModel.set(ScrimProperties.TOP_MARGIN, newHeight);
+        mTabStripHeightSupplier.addObserver(mTabStripHeightChangeCallback);
     }
 
     @Override
@@ -99,6 +106,10 @@
         }
     }
 
+    public void destroy() {
+        mTabStripHeightSupplier.removeObserver(mTabStripHeightChangeCallback);
+    }
+
     /**
      * @return Whether the scrim should wait to be shown until after the omnibox is done
      *         animating.
@@ -106,4 +117,8 @@
     private boolean showScrimAfterAnimationCompletes() {
         return mLocationBarDataProvider.getNewTabPageDelegate().isLocationBarShown();
     }
+
+    PropertyModel getScrimModelForTesting() {
+        return mScrimModel;
+    }
 }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/LocationBarFocusScrimHandlerTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/LocationBarFocusScrimHandlerTest.java
index d24327c..264afca 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/LocationBarFocusScrimHandlerTest.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/LocationBarFocusScrimHandlerTest.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.toolbar;
 
+import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
@@ -18,14 +19,18 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
 
+import org.chromium.base.Callback;
+import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.chrome.browser.omnibox.LocationBarDataProvider;
 import org.chromium.chrome.browser.omnibox.NewTabPageDelegate;
 import org.chromium.components.browser_ui.widget.scrim.ScrimCoordinator;
+import org.chromium.components.browser_ui.widget.scrim.ScrimProperties;
 
 /** Unit tests for LocationBarFocusScrimHandler. */
 @RunWith(BaseRobolectricTestRunner.class)
@@ -39,6 +44,7 @@
     @Mock private Configuration mConfiguration;
     @Mock private ScrimCoordinator mScrimCoordinator;
     @Mock private NewTabPageDelegate mNewTabPageDelegate;
+    @Mock private ObservableSupplier<Integer> mTabStripHeightSupplier;
 
     LocationBarFocusScrimHandler mScrimHandler;
 
@@ -54,7 +60,8 @@
                         mContext,
                         mLocationBarDataProvider,
                         mClickDelegate,
-                        mScrimTarget);
+                        mScrimTarget,
+                        mTabStripHeightSupplier);
     }
 
     @Test
@@ -84,4 +91,19 @@
         mScrimHandler.onUrlAnimationFinished(true);
         verify(mScrimCoordinator).showScrim(any());
     }
+
+    @Test
+    public void testTabStripHeightChangeCallback() {
+        ArgumentCaptor<Callback<Integer>> captor = ArgumentCaptor.forClass(Callback.class);
+        verify(mTabStripHeightSupplier).addObserver(captor.capture());
+        Callback<Integer> tabStripHeightChangeCallback = captor.getValue();
+        int newTabStripHeight =
+                mContext.getResources()
+                        .getDimensionPixelSize(org.chromium.chrome.R.dimen.tab_strip_height);
+        tabStripHeightChangeCallback.onResult(newTabStripHeight);
+        assertEquals(
+                "Scrim top margin should be updated when tab strip height changes.",
+                newTabStripHeight,
+                mScrimHandler.getScrimModelForTesting().get(ScrimProperties.TOP_MARGIN));
+    }
 }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ActionModeController.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ActionModeController.java
index 50a435c..eb5f698 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ActionModeController.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ActionModeController.java
@@ -14,6 +14,7 @@
 
 import androidx.appcompat.app.ActionBar;
 
+import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.chrome.browser.toolbar.R;
 
 /**
@@ -26,7 +27,7 @@
     private ToolbarActionModeCallback mToolbarActionModeCallback;
     private ObjectAnimator mCurrentAnimation;
     private boolean mShowingActionMode;
-    private float mTabStripHeight;
+    private ObservableSupplier<Integer> mTabStripHeightSupplier;
     private final Context mContext;
     private final ActionBarDelegate mActionBarDelegate;
 
@@ -75,23 +76,21 @@
     /**
      * Creates the {@link ActionModeController} and ties it to an action bar using the given action
      * bar delegate.
+     *
      * @param actionBarDelegate The delegate for communicating with toolbar for animation.
      * @param toolbarActionModeCallback The callback for communicating action mode changes.
+     * @param tabStripHeightSupplier Supplier for the tab strip height.
      */
     public ActionModeController(
             Context context,
             ActionBarDelegate actionBarDelegate,
-            ToolbarActionModeCallback toolbarActionModeCallback) {
+            ToolbarActionModeCallback toolbarActionModeCallback,
+            ObservableSupplier<Integer> tabStripHeightSupplier) {
         mActionBarDelegate = actionBarDelegate;
         mContext = context;
         mToolbarActionModeCallback = toolbarActionModeCallback;
         mToolbarActionModeCallback.setActionModeController(this);
-        mTabStripHeight = mContext.getResources().getDimension(R.dimen.tab_strip_height);
-    }
-
-    /** Overrides the preset height of the tab strip. */
-    public void setTabStripHeight(int tabStripHeight) {
-        mTabStripHeight = tabStripHeight;
+        mTabStripHeightSupplier = tabStripHeightSupplier;
     }
 
     /**
@@ -133,7 +132,7 @@
     public void startShowAnimation() {
         if (mCurrentAnimation != null) mCurrentAnimation.cancel();
 
-        int curHeight = queryCurrentActionBarHeight() - (int) mTabStripHeight;
+        int curHeight = queryCurrentActionBarHeight() - getTabStripHeight();
         mCurrentAnimation =
                 ObjectAnimator.ofInt(
                                 mActionBarDelegate,
@@ -155,7 +154,7 @@
                     public void onAnimationUpdate(ValueAnimator animation) {
                         ActionBar actionBar = mActionBarDelegate.getSupportActionBar();
                         if (actionBar != null) {
-                            int newHeight = queryCurrentActionBarHeight() - (int) mTabStripHeight;
+                            int newHeight = queryCurrentActionBarHeight() - getTabStripHeight();
                             animation.setIntValues(newHeight < 0 ? 0 : newHeight);
                         }
                     }
@@ -166,6 +165,10 @@
         mShowingActionMode = true;
     }
 
+    private int getTabStripHeight() {
+        return mTabStripHeightSupplier.get();
+    }
+
     /** Hide animation for the textview if the action bar is not visible. */
     public void startHideAnimation() {
         if (!mShowingActionMode) return;
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabStripTransitionCoordinator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabStripTransitionCoordinator.java
index 685a1a9..0e7549d 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabStripTransitionCoordinator.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabStripTransitionCoordinator.java
@@ -11,6 +11,7 @@
 import android.view.View;
 import android.view.View.OnLayoutChangeListener;
 import android.view.ViewGroup;
+import android.view.ViewStub;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -313,13 +314,19 @@
         View toolbarHairline = mControlContainer.findViewById(R.id.toolbar_hairline);
         updateTopMargin(toolbarHairline, topControlHeight);
 
-        // optionally, update the find toolbar.
-        View findToolbar = mControlContainer.findViewById(R.id.find_toolbar);
-        if (findToolbar != null) {
-            updateTopMargin(findToolbar, mTabStripHeight);
+        // Optionally, update the find toolbar and toolbar drop target views.
+        updateViewStubTopMargin(R.id.find_toolbar_stub, mTabStripHeight);
+        updateViewStubTopMargin(R.id.target_view_stub, mTabStripHeight);
+    }
+
+    private void updateViewStubTopMargin(int viewStubResourceId, int topMargin) {
+        View viewStub = mControlContainer.findViewById(viewStubResourceId);
+        if (viewStub.getParent() != null) {
+            // View is not yet inflated.
+            updateTopMargin(viewStub, topMargin);
         } else {
-            View findToolbarStub = mControlContainer.findViewById(R.id.find_toolbar_stub);
-            updateTopMargin(findToolbarStub, mTabStripHeight);
+            View view = mControlContainer.findViewById(((ViewStub) viewStub).getInflatedId());
+            updateTopMargin(view, topMargin);
         }
 
         for (var observer : mTabStripHeightObservers) {
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabStripTransitionCoordinatorUnitTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabStripTransitionCoordinatorUnitTest.java
index 298f620..442038b5 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabStripTransitionCoordinatorUnitTest.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabStripTransitionCoordinatorUnitTest.java
@@ -18,6 +18,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup.MarginLayoutParams;
+import android.view.ViewParent;
 import android.widget.FrameLayout;
 
 import androidx.annotation.Nullable;
@@ -286,6 +287,10 @@
                 tabStripHeight,
                 mSpyControlContainer.findToolbar.getTopMargin());
         Assert.assertEquals(
+                "Top margin is wrong for dropTargetView.",
+                tabStripHeight,
+                mSpyControlContainer.dropTargetView.getTopMargin());
+        Assert.assertEquals(
                 "Top margin is wrong for toolbarHairline.",
                 tabStripHeight + TEST_TOOLBAR_HEIGHT,
                 mSpyControlContainer.toolbarHairline.getTopMargin());
@@ -333,6 +338,7 @@
         public TestView toolbarLayout;
         public TestView toolbarHairline;
         public TestView findToolbar;
+        public TestView dropTargetView;
 
         @Nullable public View.OnLayoutChangeListener onLayoutChangeListener;
 
@@ -346,9 +352,19 @@
             doReturn(controlContainer.toolbarHairline)
                     .when(controlContainer)
                     .findViewById(R.id.toolbar_hairline);
+
+            // Initialize a non-null ViewParent for common use by the following control_container
+            // child views only for the purpose of testing.
+            var viewParent = Mockito.spy(ViewParent.class);
             doReturn(controlContainer.findToolbar)
                     .when(controlContainer)
-                    .findViewById(R.id.find_toolbar);
+                    .findViewById(R.id.find_toolbar_stub);
+            doReturn(controlContainer.dropTargetView)
+                    .when(controlContainer)
+                    .findViewById(R.id.target_view_stub);
+            doReturn(viewParent).when(controlContainer.findToolbar).getParent();
+            doReturn(viewParent).when(controlContainer.dropTargetView).getParent();
+
             doAnswer(args -> context.getResources().getDisplayMetrics().widthPixels)
                     .when(controlContainer)
                     .getWidth();
@@ -368,8 +384,10 @@
 
             toolbarLayout = Mockito.spy(new TestView(context, attrs));
             findToolbar = Mockito.spy(new TestView(context, attrs));
+            dropTargetView = Mockito.spy(new TestView(context, attrs));
             when(toolbarLayout.getHeight()).thenReturn(TEST_TOOLBAR_HEIGHT);
             when(findToolbar.getHeight()).thenReturn(TEST_TOOLBAR_HEIGHT);
+            when(dropTargetView.getHeight()).thenReturn(TEST_TOOLBAR_HEIGHT);
             toolbarHairline = new TestView(context, attrs);
 
             MarginLayoutParams sourceParams =
@@ -383,6 +401,7 @@
             sourceParams.height = TEST_TOOLBAR_HEIGHT;
             addView(toolbarLayout, new MarginLayoutParams(sourceParams));
             addView(findToolbar, new MarginLayoutParams(sourceParams));
+            addView(dropTargetView, new MarginLayoutParams(sourceParams));
         }
     }
 
diff --git a/chrome/browser/ui/ash/accelerator_metadata_unittest.cc b/chrome/browser/ui/ash/accelerator_metadata_unittest.cc
index 4e37ec4..26603eb 100644
--- a/chrome/browser/ui/ash/accelerator_metadata_unittest.cc
+++ b/chrome/browser/ui/ash/accelerator_metadata_unittest.cc
@@ -18,11 +18,11 @@
 namespace {
 
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
-// Internal builds add an extra accelerator for the Feedback app.
+// Internal builds add two extra accelerator for the Feedback app.
 // The total number of Chrome accelerators (available on Chrome OS).
-constexpr int kChromeAcceleratorsTotalNum = 103;
+constexpr int kChromeAcceleratorsTotalNum = 104;
 // The hash of Chrome accelerators (available on Chrome OS).
-constexpr char kChromeAcceleratorsHash[] = "e9e2edcc3a1a7332c960f7b3a00ee8cc";
+constexpr char kChromeAcceleratorsHash[] = "5b47444cf7dc4cc78a4384cacb617997";
 #else
 // The total number of Chrome accelerators (available on Chrome OS).
 constexpr int kChromeAcceleratorsTotalNum = 102;
diff --git a/chrome/browser/ui/ash/app_list/app_list_integration_test.cc b/chrome/browser/ui/ash/app_list/app_list_interactive_uitest.cc
similarity index 94%
rename from chrome/browser/ui/ash/app_list/app_list_integration_test.cc
rename to chrome/browser/ui/ash/app_list/app_list_interactive_uitest.cc
index 088fd28..9222ac8d 100644
--- a/chrome/browser/ui/ash/app_list/app_list_integration_test.cc
+++ b/chrome/browser/ui/ash/app_list/app_list_interactive_uitest.cc
@@ -15,13 +15,13 @@
 namespace ash {
 namespace {
 
-using AppListIntegrationTest = InteractiveAshTest;
+using AppListInteractiveUiTest = InteractiveAshTest;
 
 // Basic smoke test of the bubble launcher.
 // Contacts: chromeos-launcher@google.com, chromeos-sw-engprod@google.com
 // Ported from Tast by: jamescook@chromium.org
 // BugComponent: b:1288350
-IN_PROC_BROWSER_TEST_F(AppListIntegrationTest, BubbleSmoke) {
+IN_PROC_BROWSER_TEST_F(AppListInteractiveUiTest, BubbleSmoke) {
   base::AddFeatureIdTagToTestResult(
       "screenplay-90e4fecc-d2ea-40dc-b9db-eb9d61089e22");
 
diff --git a/chrome/browser/ui/ash/desks/desks_integration_test.cc b/chrome/browser/ui/ash/desks/desks_interactive_uitest.cc
similarity index 98%
rename from chrome/browser/ui/ash/desks/desks_integration_test.cc
rename to chrome/browser/ui/ash/desks/desks_interactive_uitest.cc
index 1f4f916f..f4ac11a 100644
--- a/chrome/browser/ui/ash/desks/desks_integration_test.cc
+++ b/chrome/browser/ui/ash/desks/desks_interactive_uitest.cc
@@ -49,7 +49,7 @@
 DEFINE_LOCAL_STATE_IDENTIFIER_VALUE(DeskBarExpandedObserver,
                                     kDeskBarExpandedState);
 
-class DesksIntegrationTest : public InteractiveAshTest {
+class DesksInteractiveUiTest : public InteractiveAshTest {
  public:
   // This function is used to name the DeskMiniView that is associated with the
   // desk at `desk_index`. This will find the right view regardless of how the
@@ -72,7 +72,7 @@
   }
 };
 
-IN_PROC_BROWSER_TEST_F(DesksIntegrationTest, DesksBasic) {
+IN_PROC_BROWSER_TEST_F(DesksInteractiveUiTest, DesksBasic) {
   base::AddFeatureIdTagToTestResult(
       "screenplay-c873d6a0-8e97-4a94-bb28-c1b9e6af4a51");
   SetupContextWidget();
diff --git a/chrome/browser/ui/ash/glanceables/glanceables_browsertest.cc b/chrome/browser/ui/ash/glanceables/glanceables_browsertest.cc
index 687ecd0c..d8ae585 100644
--- a/chrome/browser/ui/ash/glanceables/glanceables_browsertest.cc
+++ b/chrome/browser/ui/ash/glanceables/glanceables_browsertest.cc
@@ -12,6 +12,7 @@
 #include "ash/glanceables/common/glanceables_view_id.h"
 #include "ash/glanceables/glanceables_controller.h"
 #include "ash/glanceables/tasks/glanceables_task_view.h"
+#include "ash/glanceables/tasks/glanceables_task_view_v2.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/shell.h"
 #include "ash/style/combobox.h"
@@ -170,11 +171,6 @@
     return current_items;
   }
 
-  GlanceablesTaskView* GetTaskItemView(int item_index) {
-    return views::AsViewClass<GlanceablesTaskView>(
-        GetTasksItemContainerView()->children()[item_index]);
-  }
-
   ClassroomBubbleStudentView* GetStudentView() const {
     return GetGlanceableTrayBubble()->GetClassroomStudentView();
   }
@@ -226,11 +222,18 @@
 };
 
 class GlanceablesMvpBrowserTest : public GlanceablesBrowserTest {
+ public:
   void SetUpOnMainThread() override {
     GlanceablesBrowserTest::SetUpOnMainThread();
     base::AddFeatureIdTagToTestResult(
         "screenplay-ace3b729-5402-40cd-b2bf-d488bc95b7e2");
   }
+
+  // Returns the task view at `item_index`.
+  GlanceablesTaskView* GetTaskItemView(int item_index) {
+    return views::AsViewClass<GlanceablesTaskView>(
+        GetTasksItemContainerView()->children()[item_index]);
+  }
 };
 
 IN_PROC_BROWSER_TEST_F(GlanceablesMvpBrowserTest, OpenStudentCourseItemURL) {
@@ -474,6 +477,13 @@
 }
 
 class GlanceablesWithAddEditBrowserTest : public GlanceablesBrowserTest {
+ public:
+  // Returns the task view at `item_index`.
+  GlanceablesTaskViewV2* GetTaskItemView(int item_index) {
+    return views::AsViewClass<GlanceablesTaskViewV2>(
+        GetTasksItemContainerView()->children()[item_index]);
+  }
+
  private:
   base::test::ScopedFeatureList features_{
       features::kGlanceablesTimeManagementStableLaunch};
diff --git a/chrome/browser/ui/ash/quick_settings_integration_test.cc b/chrome/browser/ui/ash/quick_settings_integration_test.cc
index 3ad8c4a..ad61fdf 100644
--- a/chrome/browser/ui/ash/quick_settings_integration_test.cc
+++ b/chrome/browser/ui/ash/quick_settings_integration_test.cc
@@ -14,7 +14,7 @@
 #include "chrome/browser/ash/crosapi/crosapi_manager.h"
 #include "chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.h"
 #include "chrome/common/webui_url_constants.h"
-#include "chrome/test/base/chromeos/crosier/interactive_ash_test.h"
+#include "chrome/test/base/chromeos/crosier/ash_integration_test.h"
 #include "chromeos/ash/components/standalone_browser/standalone_browser_features.h"
 #include "components/strings/grit/components_strings.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -33,11 +33,11 @@
   return Shell::Get()->system_tray_model()->enterprise_domain();
 }
 
-class QuickSettingsIntegrationTest : public InteractiveAshTest {
+class QuickSettingsIntegrationTest : public AshIntegrationTest {
  public:
-  // InteractiveAshTest:
+  // AshIntegrationTest:
   void SetUpOnMainThread() override {
-    InteractiveAshTest::SetUpOnMainThread();
+    AshIntegrationTest::SetUpOnMainThread();
 
     // Ensure the OS Settings system web app (SWA) is installed.
     InstallSystemApps();
@@ -95,9 +95,6 @@
                   Log("Test complete"));
 }
 
-// Testing with Lacros requires a VM or DUT.
-#if BUILDFLAG(IS_CHROMEOS_DEVICE)
-
 // Observes the aura environment to detect the Lacros window title.
 class LacrosWindowTitleObserver
     : public ui::test::ObservationStateObserver<std::u16string,
@@ -157,7 +154,7 @@
         ash::standalone_browser::features::kLacrosOnly);
   }
 
-  // InteractiveAshTest:
+  // AshIntegrationTest:
   void SetUpCommandLine(base::CommandLine* command_line) override {
     QuickSettingsIntegrationTest::SetUpCommandLine(command_line);
     SetUpCommandLineForLacros(command_line);
@@ -212,7 +209,5 @@
       Log("Test complete"));
 }
 
-#endif  // BUILDFLAG(IS_CHROMEOS_DEVICE)
-
 }  // namespace
 }  // namespace ash
diff --git a/chrome/browser/ui/ash/shelf/shelf_integration_test.cc b/chrome/browser/ui/ash/shelf/shelf_integration_test.cc
index cd2441e..ffb908e4 100644
--- a/chrome/browser/ui/ash/shelf/shelf_integration_test.cc
+++ b/chrome/browser/ui/ash/shelf/shelf_integration_test.cc
@@ -15,8 +15,8 @@
 #include "chrome/browser/ash/file_manager/app_id.h"
 #include "chrome/browser/ui/ash/shelf/shelf_context_menu.h"
 #include "chrome/browser/web_applications/web_app_id_constants.h"
+#include "chrome/test/base/chromeos/crosier/ash_integration_test.h"
 #include "chrome/test/base/chromeos/crosier/aura_window_title_observer.h"
-#include "chrome/test/base/chromeos/crosier/interactive_ash_test.h"
 #include "components/app_constants/constants.h"
 #include "content/public/test/browser_test.h"
 #include "ui/aura/env.h"
@@ -34,7 +34,7 @@
 const char16_t kBrowserWindowTitle[] = u"Chromium - New Tab";
 #endif
 
-class ShelfIntegrationTest : public InteractiveAshTest {
+class ShelfIntegrationTest : public AshIntegrationTest {
  public:
   ShelfIntegrationTest()
       : zero_duration_scoped_animation_scale_mode_(
diff --git a/chrome/browser/ui/autofill/autofill_keyboard_accessory_adapter.cc b/chrome/browser/ui/autofill/autofill_keyboard_accessory_adapter.cc
index 69b7be3..5c0e7a2 100644
--- a/chrome/browser/ui/autofill/autofill_keyboard_accessory_adapter.cc
+++ b/chrome/browser/ui/autofill/autofill_keyboard_accessory_adapter.cc
@@ -222,12 +222,17 @@
   return true;
 }
 
-void AutofillKeyboardAccessoryAdapter::SelectSuggestion(
-    std::optional<size_t> index) {
+void AutofillKeyboardAccessoryAdapter::SelectSuggestion(int index) {
   if (!controller_)
     return;
-  controller_->SelectSuggestion(
-      index ? std::optional<size_t>(OffsetIndexFor(*index)) : std::nullopt);
+  controller_->SelectSuggestion(OffsetIndexFor(index));
+}
+
+void AutofillKeyboardAccessoryAdapter::UnselectSuggestion() {
+  if (!controller_) {
+    return;
+  }
+  controller_->UnselectSuggestion();
 }
 
 // AutofillPopupViewDelegate implementation
diff --git a/chrome/browser/ui/autofill/autofill_keyboard_accessory_adapter.h b/chrome/browser/ui/autofill/autofill_keyboard_accessory_adapter.h
index 8a067be8..224b812b 100644
--- a/chrome/browser/ui/autofill/autofill_keyboard_accessory_adapter.h
+++ b/chrome/browser/ui/autofill/autofill_keyboard_accessory_adapter.h
@@ -32,7 +32,7 @@
 class AutofillKeyboardAccessoryAdapter : public AutofillPopupView,
                                          public AutofillPopupController {
  public:
-  AutofillKeyboardAccessoryAdapter(
+  explicit AutofillKeyboardAccessoryAdapter(
       base::WeakPtr<AutofillPopupController> controller);
 
   AutofillKeyboardAccessoryAdapter(const AutofillKeyboardAccessoryAdapter&) =
@@ -106,7 +106,8 @@
   bool RemoveSuggestion(
       int index,
       AutofillMetrics::SingleEntryRemovalMethod removal_method) override;
-  void SelectSuggestion(std::optional<size_t> index) override;
+  void SelectSuggestion(int index) override;
+  void UnselectSuggestion() override;
   PopupType GetPopupType() const override;
   bool ShouldIgnoreMouseObservedOutsideItemBoundsCheck() const override;
   base::WeakPtr<AutofillPopupController> OpenSubPopup(
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller.h b/chrome/browser/ui/autofill/autofill_popup_controller.h
index 3ddbef6..5163f323 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller.h
+++ b/chrome/browser/ui/autofill/autofill_popup_controller.h
@@ -28,7 +28,10 @@
 
   // Selects the suggestion with `index`. For fillable items, this will trigger
   // preview. For other items, it does not do anything.
-  virtual void SelectSuggestion(std::optional<size_t> index) = 0;
+  virtual void SelectSuggestion(int index) = 0;
+
+  // Unselect currently selected suggestion, noop if nothing is selected.
+  virtual void UnselectSuggestion() = 0;
 
   // Accepts the suggestion at `index`. The suggestion will only be accepted if
   // the popup has been shown for at least `show_threshold` compared to
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
index 8170b751..e6b3f68 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
@@ -24,10 +24,12 @@
 #include "chrome/browser/feature_engagement/tracker_factory.h"
 #include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h"
 #include "chrome/browser/ui/autofill/autofill_popup_view.h"
+#include "components/autofill/content/browser/scoped_autofill_managers_observation.h"
 #include "components/autofill/core/browser/metrics/autofill_metrics.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/ui/autofill_popup_delegate.h"
 #include "components/autofill/core/browser/ui/popup_item_ids.h"
+#include "components/autofill/core/browser/ui/popup_types.h"
 #include "components/autofill/core/browser/ui/suggestion.h"
 #include "components/autofill/core/common/autofill_features.h"
 #include "components/feature_engagement/public/feature_constants.h"
@@ -171,6 +173,15 @@
   }
 }
 
+void AutofillPopupControllerImpl::OnBeforeTextFieldDidChange(
+    AutofillManager& manager,
+    FormGlobalId form,
+    FieldGlobalId field) {
+  // This method is only called for popups with a Compose entry. In this case,
+  // an edit on a field should lead to the popup hiding.
+  Hide(PopupHidingReason::kFieldValueChanged);
+}
+
 void AutofillPopupControllerImpl::Show(
     std::vector<Suggestion> suggestions,
     AutofillSuggestionTriggerSource trigger_source,
@@ -236,6 +247,16 @@
     rfh->GetRenderWidgetHost()->AddKeyPressEventCallback(
         key_press_observer_.handler);
 
+    // It suffices if the root popup observes changes in form elements.
+    // Currently, this is only relevant for Compose.
+    if (suggestions_.size() == 1 &&
+        suggestions_[0].popup_item_id == PopupItemId::kCompose) {
+      autofill_managers_observation_.Observe(
+          web_contents(),
+          ScopedAutofillManagersObservation::InitializationPolicy::
+              kObservePreexistingManagers);
+    }
+
     delegate_->OnPopupShown();
   }
 }
@@ -322,6 +343,7 @@
     }
     key_press_observer_ = {};
   }
+  autofill_managers_observation_.Reset();
   AutofillMetrics::LogAutofillPopupHidingReason(reason);
   HideViewAndDie();
 }
@@ -645,25 +667,24 @@
   return true;
 }
 
-void AutofillPopupControllerImpl::SelectSuggestion(
-    std::optional<size_t> index) {
+void AutofillPopupControllerImpl::SelectSuggestion(int index) {
+  CHECK_LT(index, static_cast<int>(suggestions_.size()));
+
   if (IsMouseLocked()) {
     Hide(PopupHidingReason::kMouseLocked);
     return;
   }
 
-  if (index) {
-    DCHECK_LT(*index, suggestions_.size());
-    if (!CanAccept(GetSuggestionAt(*index).popup_item_id)) {
-      index = std::nullopt;
-    }
+  if (!CanAccept(GetSuggestionAt(index).popup_item_id)) {
+    UnselectSuggestion();
+    return;
   }
 
-  if (index) {
-    delegate_->DidSelectSuggestion(GetSuggestionAt(*index));
-  } else {
-    delegate_->ClearPreviewedForm();
-  }
+  delegate_->DidSelectSuggestion(GetSuggestionAt(index));
+}
+
+void AutofillPopupControllerImpl::UnselectSuggestion() {
+  delegate_->ClearPreviewedForm();
 }
 
 PopupType AutofillPopupControllerImpl::GetPopupType() const {
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.h b/chrome/browser/ui/autofill/autofill_popup_controller_impl.h
index bdd91a72..2921d115 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.h
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.h
@@ -16,6 +16,8 @@
 #include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h"
 #include "chrome/browser/ui/autofill/autofill_popup_controller.h"
 #include "chrome/browser/ui/autofill/popup_controller_common.h"
+#include "components/autofill/content/browser/scoped_autofill_managers_observation.h"
+#include "components/autofill/core/browser/autofill_manager.h"
 #include "components/autofill/core/browser/ui/popup_types.h"
 #include "components/autofill/core/common/aliases.h"
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
@@ -69,6 +71,7 @@
 class AutofillPopupControllerImpl
     : public AutofillPopupController,
       public content::WebContentsObserver,
+      public AutofillManager::Observer,
       public PictureInPictureWindowManager::Observer,
       public ExpandablePopupParentControllerImpl {
  public:
@@ -115,7 +118,8 @@
 
   // AutofillPopupController:
   void OnSuggestionsChanged() override;
-  void SelectSuggestion(std::optional<size_t> index) override;
+  void SelectSuggestion(int index) override;
+  void UnselectSuggestion() override;
   void AcceptSuggestion(int index, base::TimeTicks event_time) override;
   void PerformButtonActionForSuggestion(int index) override;
   bool RemoveSuggestion(
@@ -207,6 +211,11 @@
       content::NavigationHandle* navigation_handle) override;
   void OnVisibilityChanged(content::Visibility visibility) override;
 
+  // AutofillManager::Observer:
+  void OnBeforeTextFieldDidChange(AutofillManager& manager,
+                                  FormGlobalId form,
+                                  FieldGlobalId field) override;
+
   // Clear the internal state of the controller. This is needed to ensure that
   // when the popup is reused it doesn't leak values between uses.
   void ClearState();
@@ -266,6 +275,8 @@
                           PictureInPictureWindowManager::Observer>
       picture_in_picture_window_observation_{this};
 
+  ScopedAutofillManagersObservation autofill_managers_observation_{this};
+
   // Callback invoked to try to show the password migration warning on Android.
   // Used to facilitate testing.
   // TODO(crbug.com/1454469): Remove when the warning isn't needed anymore.
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl_unittest.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl_unittest.cc
index 3fe67d2..29a6f25 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_impl_unittest.cc
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl_unittest.cc
@@ -39,8 +39,10 @@
 #include "components/autofill/core/browser/test_personal_data_manager.h"
 #include "components/autofill/core/browser/ui/autofill_popup_delegate.h"
 #include "components/autofill/core/browser/ui/popup_item_ids.h"
+#include "components/autofill/core/browser/ui/popup_types.h"
 #include "components/autofill/core/browser/ui/suggestion.h"
 #include "components/autofill/core/common/aliases.h"
+#include "components/autofill/core/common/unique_ids.h"
 #include "components/password_manager/core/common/password_manager_features.h"
 #include "components/prefs/pref_service.h"
 #include "components/strings/grit/components_strings.h"
@@ -848,6 +850,11 @@
   EXPECT_EQ(0, controller->GetLineCountForTesting());
 }
 
+TEST_F(AutofillPopupControllerImplTest, UnselectingClearsPreview) {
+  EXPECT_CALL(manager().external_delegate(), ClearPreviewedForm());
+  client().popup_controller(manager()).UnselectSuggestion();
+}
+
 TEST_F(AutofillPopupControllerImplTest, HidingClearsPreview) {
   EXPECT_CALL(manager().external_delegate(), ClearPreviewedForm());
   EXPECT_CALL(manager().external_delegate(), OnPopupHidden());
@@ -1214,6 +1221,28 @@
               Optional(Field(&PopupScreenLocation::bounds, kSampleRect)));
 }
 
+// Tests that a change to a text field hides a popup with a Compose suggestion.
+TEST_F(AutofillPopupControllerImplTest, HidesOnFieldChangeForComposeEntries) {
+  ShowSuggestions(manager(), {PopupItemId::kCompose});
+  EXPECT_CALL(client().popup_controller(manager()),
+              Hide(PopupHidingReason::kFieldValueChanged));
+  manager().NotifyObservers(
+      &AutofillManager::Observer::OnBeforeTextFieldDidChange, FormGlobalId(),
+      FieldGlobalId());
+}
+
+// Tests that a change to a text field does not hide a popup with an
+// Autocomplete suggestion.
+TEST_F(AutofillPopupControllerImplTest,
+       DoeNotHideOnFieldChangeForNonComposeEntries) {
+  ShowSuggestions(manager(), {PopupItemId::kAutocompleteEntry});
+  EXPECT_CALL(client().popup_controller(manager()), Hide).Times(0);
+  manager().NotifyObservers(
+      &AutofillManager::Observer::OnBeforeTextFieldDidChange, FormGlobalId(),
+      FieldGlobalId());
+  Mock::VerifyAndClearExpectations(&client().popup_controller(manager()));
+}
+
 #if !BUILDFLAG(IS_CHROMEOS_ASH)
 class MockAxTreeManager : public ui::AXTreeManager {
  public:
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_interactive_uitest.cc b/chrome/browser/ui/autofill/autofill_popup_controller_interactive_uitest.cc
index 6e93d840..1ad0700c 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_interactive_uitest.cc
@@ -215,7 +215,7 @@
                                     {u"suggestion4", u"suggestion4"}};
   client->UpdateAutofillPopupDataListValues(rows);
   int original_suggestions_count = controller->GetLineCount();
-  controller->SelectSuggestion(3u);
+  controller->SelectSuggestion(3);
 
   // Replace the list with the smaller one.
   rows = {{u"suggestion1", u"suggestion1"}};
@@ -223,7 +223,7 @@
   // Make sure that previously selected line #3 doesn't exist.
   ASSERT_LT(controller->GetLineCount(), original_suggestions_count);
   // Selecting a new line should not crash.
-  controller->SelectSuggestion(0u);
+  controller->SelectSuggestion(0);
 }
 
 }  // namespace autofill
diff --git a/chrome/browser/ui/hats/trust_safety_sentiment_service.cc b/chrome/browser/ui/hats/trust_safety_sentiment_service.cc
index bfa9c10..40d21f5 100644
--- a/chrome/browser/ui/hats/trust_safety_sentiment_service.cc
+++ b/chrome/browser/ui/hats/trust_safety_sentiment_service.cc
@@ -459,6 +459,7 @@
   product_specific_data["Is downloads page UI"] = false;
   product_specific_data["Is download prompt UI"] = false;
   product_specific_data["User proceeded past warning"] = false;
+  product_specific_data["Is subpage UI"] = false;
   switch (surface) {
     case DownloadItemWarningData::WarningSurface::BUBBLE_MAINPAGE:
       product_specific_data["Is mainpage UI"] = true;
diff --git a/chrome/browser/ui/login/login_handler.cc b/chrome/browser/ui/login/login_handler.cc
index fe3ea4a1..a27bef5f 100644
--- a/chrome/browser/ui/login/login_handler.cc
+++ b/chrome/browser/ui/login/login_handler.cc
@@ -11,7 +11,6 @@
 #include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/functional/bind.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/lock.h"
@@ -63,21 +62,6 @@
 
 namespace {
 
-// Auth prompt types for UMA. Do not reorder or delete entries; only add to the
-// end.
-enum AuthPromptType {
-  AUTH_PROMPT_TYPE_WITH_INTERSTITIAL = 0,
-  AUTH_PROMPT_TYPE_MAIN_FRAME = 1,
-  AUTH_PROMPT_TYPE_SUBRESOURCE_SAME_ORIGIN = 2,
-  AUTH_PROMPT_TYPE_SUBRESOURCE_CROSS_ORIGIN = 3,
-  AUTH_PROMPT_TYPE_ENUM_COUNT = 4
-};
-
-void RecordHttpAuthPromptType(AuthPromptType prompt_type) {
-  UMA_HISTOGRAM_ENUMERATION("Net.HttpAuthPromptType", prompt_type,
-                            AUTH_PROMPT_TYPE_ENUM_COUNT);
-}
-
 // All login handlers should be tracked in this global singleton.
 using LoginHandlerVector = std::vector<base::WeakPtr<LoginHandler>>;
 LoginHandlerVector& GetAllLoginHandlers() {
@@ -529,17 +513,11 @@
   // rare due to credential caching, we commit an interstitial for all
   // main-frame navigations.
   if (is_request_for_main_frame) {
-    RecordHttpAuthPromptType(AUTH_PROMPT_TYPE_WITH_INTERSTITIAL);
     CancelAuth();
     return;
   }
 
   prompt_started_ = true;
-  RecordHttpAuthPromptType(
-      web_contents_->GetLastCommittedURL().DeprecatedGetOriginAsURL() !=
-              request_url.DeprecatedGetOriginAsURL()
-          ? AUTH_PROMPT_TYPE_SUBRESOURCE_CROSS_ORIGIN
-          : AUTH_PROMPT_TYPE_SUBRESOURCE_SAME_ORIGIN);
   ShowLoginPrompt(request_url);
 }
 
diff --git a/chrome/browser/ui/tab_contents/core_tab_helper.cc b/chrome/browser/ui/tab_contents/core_tab_helper.cc
index bad6e86..17dcd335 100644
--- a/chrome/browser/ui/tab_contents/core_tab_helper.cc
+++ b/chrome/browser/ui/tab_contents/core_tab_helper.cc
@@ -82,6 +82,8 @@
 constexpr int kImageSearchThumbnailMaxWidth = 600;
 constexpr int kImageSearchThumbnailMaxHeight = 600;
 constexpr char kUnifiedSidePanelVersion[] = "1";
+constexpr int kEncodingQualityJpeg = 40;
+constexpr int kEncodingQualityWebp = 45;
 
 bool NeedsDownscale(gfx::Image image) {
   return (image.Height() * image.Width() >
@@ -132,24 +134,15 @@
     std::string& content_type,
     lens::mojom::ImageFormat& image_format) {
   std::vector<unsigned char> data;
-  // TODO(crbug/1486044): Encode off the main thread.
-  if (lens::features::IsWebpForImageSearchEnabled() &&
-      gfx::WebpCodec::Encode(image.AsBitmap(),
-                             lens::features::GetEncodingQualityWebp(), &data)) {
-    content_type = "image/webp";
-    image_format = lens::mojom::ImageFormat::WEBP;
-    return data;
-  } else if (lens::features::IsJpegForImageSearchEnabled() &&
-             gfx::JPEGCodec::Encode(image.AsBitmap(),
-                                    lens::features::GetEncodingQualityJpeg(),
-                                    &data)) {
+
+  if (gfx::JPEGCodec::Encode(image.AsBitmap(), kEncodingQualityJpeg, &data)) {
     content_type = "image/jpeg";
     image_format = lens::mojom::ImageFormat::JPEG;
     return data;
   }
-  // If the WebP/JPEG encoding fails, fall back to PNG.
+
   // Get the front and end of the image bytes in order to store them in the
-  // search_args to be sent as part of the PostContent in the request.
+  // search_args to be sent as part of the PostContent in the request
   size_t image_bytes_size = image.As1xPNGBytes()->size();
   const unsigned char* image_bytes_begin = image.As1xPNGBytes()->front();
   const unsigned char* image_bytes_end = image_bytes_begin + image_bytes_size;
@@ -171,6 +164,7 @@
   gfx::Size downscaled_size;
   std::vector<lens::mojom::LatencyLogPtr> log_data;
   std::vector<unsigned char> thumbnail_data;
+
   if (bitmap.isNull()) {
     return std::move(callback).Run(thumbnail_data, content_type, original_size,
                                    downscaled_size, std::move(log_data));
@@ -219,13 +213,11 @@
       lens::mojom::ImageFormat::ORIGINAL, base::Time::Now(),
       /*encoded_size_bytes=*/0));
   if (thumbnail.isOpaque() &&
-      gfx::JPEGCodec::Encode(
-          thumbnail, lens::features::GetEncodingQualityJpeg(), &encoded_data)) {
+      gfx::JPEGCodec::Encode(thumbnail, kEncodingQualityJpeg, &encoded_data)) {
     thumbnail_data.swap(encoded_data);
     content_type = "image/jpeg";
     encode_target_format = lens::mojom::ImageFormat::JPEG;
-  } else if (gfx::WebpCodec::Encode(thumbnail,
-                                    lens::features::GetEncodingQualityWebp(),
+  } else if (gfx::WebpCodec::Encode(thumbnail, kEncodingQualityWebp,
                                     &encoded_data)) {
     thumbnail_data.swap(encoded_data);
     content_type = "image/webp";
diff --git a/chrome/browser/ui/tab_contents/core_tab_helper_unittest.cc b/chrome/browser/ui/tab_contents/core_tab_helper_unittest.cc
index c2f41509..d1642d96 100644
--- a/chrome/browser/ui/tab_contents/core_tab_helper_unittest.cc
+++ b/chrome/browser/ui/tab_contents/core_tab_helper_unittest.cc
@@ -151,75 +151,7 @@
       /*expected_downscaled_width=*/1, /*expected_downscaled_height=*/300);
 }
 
-TEST(CoreTabHelperUnitTest,
-     EncodeImageIntoSearchArgs_OptimizedImageFormatsDisabled_EncodesAsPng) {
-  base::test::ScopedFeatureList features;
-  features.InitAndDisableFeature(lens::features::kLensImageFormatOptimizations);
-  gfx::Image image = gfx::test::CreateImage(100, 100);
-  TemplateURLRef::SearchTermsArgs search_args =
-      TemplateURLRef::SearchTermsArgs(std::u16string());
-
-  size_t encoded_image_size_bytes;
-  lens::mojom::ImageFormat image_format =
-      CoreTabHelper::EncodeImageIntoSearchArgs(image, encoded_image_size_bytes,
-                                               search_args);
-
-  EXPECT_FALSE(search_args.image_thumbnail_content.empty());
-  EXPECT_EQ("image/png", search_args.image_thumbnail_content_type);
-  EXPECT_EQ(313ul, encoded_image_size_bytes);
-  EXPECT_EQ(lens::mojom::ImageFormat::PNG, image_format);
-}
-
-TEST(CoreTabHelperUnitTest,
-     EncodeImageIntoSearchArgs_WebpEnabledAndEncodingSucceeds_EncodesAsWebp) {
-  base::test::ScopedFeatureList features;
-  features.InitAndEnableFeatureWithParameters(
-      lens::features::kLensImageFormatOptimizations,
-      {{"use-webp-for-image-search", "true"},
-       {"use-jpeg-for-image-search", "false"}});
-  gfx::Image image = gfx::test::CreateImage(100, 100);
-  TemplateURLRef::SearchTermsArgs search_args =
-      TemplateURLRef::SearchTermsArgs(std::u16string());
-
-  size_t encoded_image_size_bytes;
-  lens::mojom::ImageFormat image_format =
-      CoreTabHelper::EncodeImageIntoSearchArgs(image, encoded_image_size_bytes,
-                                               search_args);
-
-  EXPECT_FALSE(search_args.image_thumbnail_content.empty());
-  EXPECT_EQ("image/webp", search_args.image_thumbnail_content_type);
-  EXPECT_EQ(124ul, encoded_image_size_bytes);
-  EXPECT_EQ(lens::mojom::ImageFormat::WEBP, image_format);
-}
-
-TEST(CoreTabHelperUnitTest,
-     EncodeImageIntoSearchArgs_WebpEnabledAndEncodingFails_EncodesAsPng) {
-  base::test::ScopedFeatureList features;
-  features.InitAndEnableFeatureWithParameters(
-      lens::features::kLensImageFormatOptimizations,
-      {{"use-webp-for-image-search", "true"},
-       {"use-jpeg-for-image-search", "false"}});
-  gfx::Image image = gfx::test::CreateImage(0, 0);  // Encoding 0x0 will fail
-  TemplateURLRef::SearchTermsArgs search_args =
-      TemplateURLRef::SearchTermsArgs(std::u16string());
-
-  size_t encoded_image_size_bytes;
-  lens::mojom::ImageFormat image_format =
-      CoreTabHelper::EncodeImageIntoSearchArgs(image, encoded_image_size_bytes,
-                                               search_args);
-
-  EXPECT_EQ("image/png", search_args.image_thumbnail_content_type);
-  EXPECT_EQ(0ul, encoded_image_size_bytes);
-  EXPECT_EQ(lens::mojom::ImageFormat::PNG, image_format);
-}
-
-TEST(CoreTabHelperUnitTest,
-     EncodeImageIntoSearchArgs_JpegEnabledAndEncodingSucceeds_EncodesAsJpeg) {
-  base::test::ScopedFeatureList features;
-  features.InitAndEnableFeatureWithParameters(
-      lens::features::kLensImageFormatOptimizations,
-      {{"use-webp-for-image-search", "false"},
-       {"use-jpeg-for-image-search", "true"}});
+TEST(CoreTabHelperUnitTest, EncodeImageIntoSearchArgs_EncodesAsJpeg) {
   gfx::Image image = gfx::test::CreateImage(100, 100);
   TemplateURLRef::SearchTermsArgs search_args =
       TemplateURLRef::SearchTermsArgs(std::u16string());
@@ -236,12 +168,7 @@
 }
 
 TEST(CoreTabHelperUnitTest,
-     EncodeImageIntoSearchArgs_JpegEnabledAndEncodingFails_EncodesAsPng) {
-  base::test::ScopedFeatureList features;
-  features.InitAndEnableFeatureWithParameters(
-      lens::features::kLensImageFormatOptimizations,
-      {{"use-webp-for-image-search", "false"},
-       {"use-jpeg-for-image-search", "true"}});
+     EncodeImageIntoSearchArgs_JpegEncodingFails_EncodesAsPng) {
   gfx::Image image = gfx::test::CreateImage(0, 0);  // Encoding 0x0 will fail
   TemplateURLRef::SearchTermsArgs search_args =
       TemplateURLRef::SearchTermsArgs(std::u16string());
diff --git a/chrome/browser/ui/tabs/organization/tab_organization_service.cc b/chrome/browser/ui/tabs/organization/tab_organization_service.cc
index d090566..ae359ae 100644
--- a/chrome/browser/ui/tabs/organization/tab_organization_service.cc
+++ b/chrome/browser/ui/tabs/organization/tab_organization_service.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/flag_descriptions.h"
 #include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/organization/request_factory.h"
 #include "chrome/browser/ui/tabs/organization/tab_organization_session.h"
 #include "chrome/browser/ui/tabs/organization/tab_sensitivity_cache.h"
@@ -55,10 +56,9 @@
     if (!GetSessionForBrowser(browser)->IsComplete()) {
       return;
     } else {
-      browser_session_map_.erase(browser);
+      RemoveBrowserFromSessionMap(browser);
     }
   }
-  CreateSessionForBrowser(browser);
 
   for (TabOrganizationObserver& observer : observers_) {
     observer.OnToggleActionUIState(browser, true);
@@ -90,6 +90,7 @@
       browser_session_map_.emplace(
           browser, TabOrganizationSession::CreateSessionForBrowser(
                        browser, base_session_webcontents));
+  browser->tab_strip_model()->AddObserver(this);
 
   for (TabOrganizationObserver& observer : observers_) {
     observer.OnSessionCreated(browser, pair.first->second.get());
@@ -101,8 +102,9 @@
 TabOrganizationSession* TabOrganizationService::ResetSessionForBrowser(
     const Browser* browser,
     const content::WebContents* base_session_webcontents) {
+  browser->tab_strip_model()->RemoveObserver(this);
   if (base::Contains(browser_session_map_, browser)) {
-    browser_session_map_.erase(browser);
+    RemoveBrowserFromSessionMap(browser);
   }
 
   return CreateSessionForBrowser(browser, base_session_webcontents);
@@ -125,6 +127,36 @@
   }
 }
 
+void TabOrganizationService::OnTabStripModelChanged(
+    TabStripModel* tab_strip_model,
+    const TabStripModelChange& change,
+    const TabStripSelectionChange& selection) {
+  switch (change.type()) {
+    case TabStripModelChange::kMoved:
+    case TabStripModelChange::kSelectionOnly:
+    case TabStripModelChange::kReplaced: {
+      return;
+    }
+    // When a tab is added or removed on the tabstrip destroy the session
+    // for that browser.
+    case TabStripModelChange::kInserted:
+    case TabStripModelChange::kRemoved: {
+      const auto find_result = std::find_if(
+          browser_session_map_.begin(), browser_session_map_.end(),
+
+          [&tab_strip_model](
+              std::pair<const Browser* const,
+                        std::unique_ptr<TabOrganizationSession>>& element) {
+            return element.first->tab_strip_model() == tab_strip_model;
+          });
+      if (find_result != browser_session_map_.end()) {
+        RemoveBrowserFromSessionMap(find_result->first);
+      }
+      return;
+    }
+  }
+}
+
 void TabOrganizationService::AcceptTabOrganization(
     Browser* browser,
     TabOrganization::ID session_id,
@@ -151,7 +183,7 @@
 
   // if the session is completed, then destroy it.
   if (session->IsComplete()) {
-    browser_session_map_.erase(browser);
+    RemoveBrowserFromSessionMap(browser);
   }
 
   for (TabOrganizationObserver& observer : observers_) {
@@ -166,7 +198,6 @@
 
 void TabOrganizationService::OnActionUIDismissed(const Browser* browser) {
   trigger_backoff_->Increment();
-  browser_session_map_.erase(browser);
 }
 
 void TabOrganizationService::Shutdown() {
@@ -203,6 +234,13 @@
   EnableTabOrganizationFeatures(flags_storage.get());
 }
 
+void TabOrganizationService::RemoveBrowserFromSessionMap(
+    const Browser* browser) {
+  CHECK(base::Contains(browser_session_map_, browser));
+  browser->tab_strip_model()->RemoveObserver(this);
+  browser_session_map_.erase(browser);
+}
+
 void TabOrganizationService::EnableTabOrganizationFeatures(
     flags_ui::FlagsStorage* flags_storage) {
   about_flags::SetFeatureEntryEnabled(
diff --git a/chrome/browser/ui/tabs/organization/tab_organization_service.h b/chrome/browser/ui/tabs/organization/tab_organization_service.h
index ce2665f..b64bea6 100644
--- a/chrome/browser/ui/tabs/organization/tab_organization_service.h
+++ b/chrome/browser/ui/tabs/organization/tab_organization_service.h
@@ -14,6 +14,7 @@
 #include "chrome/browser/ui/tabs/organization/tab_organization_observer.h"
 #include "chrome/browser/ui/tabs/organization/tab_organization_session.h"
 #include "chrome/browser/ui/tabs/organization/trigger_observer.h"
+#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "components/flags_ui/pref_service_flags_storage.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/optimization_guide/core/model_execution/settings_enabled_observer.h"
@@ -30,7 +31,8 @@
 // Provides an interface for getting Organizations for tabs.
 class TabOrganizationService
     : public KeyedService,
-      public optimization_guide::SettingsEnabledObserver {
+      public optimization_guide::SettingsEnabledObserver,
+      public TabStripModelObserver {
  public:
   using BrowserSessionMap =
       std::unordered_map<const Browser*,
@@ -49,6 +51,10 @@
     return browser_session_map_;
   }
 
+  const TabSensitivityCache* tab_sensitivity_cache() const {
+    return tab_sensitivity_cache_.get();
+  }
+
   const TabOrganizationSession* GetSessionForBrowser(
       const Browser* browser) const;
   TabOrganizationSession* GetSessionForBrowser(const Browser* browser);
@@ -91,9 +97,11 @@
     observers_.RemoveObserver(observer);
   }
 
-  const TabSensitivityCache* tab_sensitivity_cache() const {
-    return tab_sensitivity_cache_.get();
-  }
+  // TabStripModelObserver.
+  void OnTabStripModelChanged(
+      TabStripModel* tab_strip_model,
+      const TabStripModelChange& change,
+      const TabStripSelectionChange& selection) override;
 
  private:
   // KeyedService:
@@ -102,6 +110,8 @@
   // optimization_guide::SettingsEnabledObserver:
   void PrepareToEnableOnRestart() override;
 
+  void RemoveBrowserFromSessionMap(const Browser* browser);
+
   void EnableTabOrganizationFeatures(flags_ui::FlagsStorage* flags_storage);
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/tabs/organization/tab_organization_service_unittest.cc b/chrome/browser/ui/tabs/organization/tab_organization_service_unittest.cc
index 482e7ab..8aead52 100644
--- a/chrome/browser/ui/tabs/organization/tab_organization_service_unittest.cc
+++ b/chrome/browser/ui/tabs/organization/tab_organization_service_unittest.cc
@@ -126,18 +126,11 @@
 
 // Service tests.
 
-TEST_F(TabOrganizationServiceTest, AddsSessionOnTrigger) {
-  Browser* browser = AddBrowser();
-  AddValidTabToBrowser(browser, 0);
-  service()->OnTriggerOccured(browser);
-  EXPECT_TRUE(base::Contains(service()->browser_session_map(), browser));
-  EXPECT_NE(service()->GetSessionForBrowser(browser), nullptr);
-}
-
 TEST_F(TabOrganizationServiceTest, DoesntAddSessionOnTriggerIfExists) {
   Browser* browser = AddBrowser();
   AddValidTabToBrowser(browser, 0);
   service()->OnTriggerOccured(browser);
+  service()->CreateSessionForBrowser(browser);
   EXPECT_TRUE(base::Contains(service()->browser_session_map(), browser));
   const TabOrganizationSession* session =
       service()->GetSessionForBrowser(browser);
@@ -151,8 +144,8 @@
 TEST_F(TabOrganizationServiceTest, EachBrowserHasADistinctSession) {
   Browser* browser1 = AddBrowser();
   Browser* browser2 = AddBrowser();
-  service()->OnTriggerOccured(browser1);
-  service()->OnTriggerOccured(browser2);
+  service()->CreateSessionForBrowser(browser1);
+  service()->CreateSessionForBrowser(browser2);
   EXPECT_NE(service()->GetSessionForBrowser(browser1),
             service()->GetSessionForBrowser(browser2));
 }
@@ -277,3 +270,20 @@
       TabOrganizationSession::CreateSessionForBrowser(browser1, base_tab);
   EXPECT_NE(session->request()->base_tab_id(), absl::nullopt);
 }
+
+TEST_F(TabOrganizationServiceTest, TabStripAddRemoveDestroysSession) {
+  Browser* browser1 = AddBrowser();
+  for (int i = 0; i < 4; i++) {
+    AddValidTabToBrowser(browser1, 0);
+  }
+
+  service()->CreateSessionForBrowser(browser1);
+  content::WebContents* contents = AddValidTabToBrowser(browser1, 0);
+  EXPECT_EQ(service()->GetSessionForBrowser(browser1), nullptr);
+
+  service()->CreateSessionForBrowser(browser1);
+  browser1->tab_strip_model()->CloseWebContentsAt(
+      browser1->tab_strip_model()->GetIndexOfWebContents(contents),
+      TabCloseTypes::CLOSE_NONE);
+  EXPECT_EQ(service()->GetSessionForBrowser(browser1), nullptr);
+}
diff --git a/chrome/browser/ui/tabs/organization/tab_organization_session.h b/chrome/browser/ui/tabs/organization/tab_organization_session.h
index 76e8636c..33b8e0db 100644
--- a/chrome/browser/ui/tabs/organization/tab_organization_session.h
+++ b/chrome/browser/ui/tabs/organization/tab_organization_session.h
@@ -12,7 +12,6 @@
 
 #include "chrome/browser/ui/tabs/organization/tab_organization.h"
 #include "chrome/browser/ui/tabs/organization/tab_organization_request.h"
-#include "third_party/abseil-cpp/absl/types/variant.h"
 
 class Browser;
 namespace Content {
diff --git a/chrome/browser/ui/views/accelerator_table.cc b/chrome/browser/ui/views/accelerator_table.cc
index 20f57e0b..8e702ab 100644
--- a/chrome/browser/ui/views/accelerator_table.cc
+++ b/chrome/browser/ui/views/accelerator_table.cc
@@ -173,6 +173,11 @@
     {ui::VKEY_PRINT, ui::EF_NONE, IDC_PRINT},
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
+#if BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
+    // Chrome OS supports search-based shortcut to open feedback app.
+    {ui::VKEY_I, ui::EF_CONTROL_DOWN | ui::EF_COMMAND_DOWN, IDC_FEEDBACK},
+#endif  // BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
+
 #if BUILDFLAG(IS_CHROMEOS)
     // Chrome OS keyboard does not have delete key, so assign it to backspace.
     {ui::VKEY_BACK, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN,
diff --git a/chrome/browser/ui/views/accelerator_table_unittest.cc b/chrome/browser/ui/views/accelerator_table_unittest.cc
index f5655b21..3f4a38c7 100644
--- a/chrome/browser/ui/views/accelerator_table_unittest.cc
+++ b/chrome/browser/ui/views/accelerator_table_unittest.cc
@@ -72,6 +72,22 @@
 #endif  // BUILDFLAG(IS_CHROMEOS)
 }
 
+TEST(AcceleratorTableTest, OpenFeedbackWithSearchBasedAccelerator) {
+  int command_id = -1;
+  for (const auto& entry : GetAcceleratorList()) {
+    if (entry.keycode == ui::VKEY_I &&
+        entry.modifiers == (ui::EF_CONTROL_DOWN | ui::EF_COMMAND_DOWN)) {
+      command_id = entry.command_id;
+    }
+  }
+
+#if BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
+  EXPECT_EQ(IDC_FEEDBACK, command_id);
+#else   // !BUILDFLAG(IS_CHROMEOS) || !BUILDFLAG(GOOGLE_CHROME_BRANDING)
+  EXPECT_EQ(-1, command_id);
+#endif  // BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
+}
+
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 TEST(AcceleratorTableTest, CheckDuplicatedAcceleratorsAsh) {
   base::flat_set<AcceleratorMapping, Cmp> accelerators(GetAcceleratorList());
diff --git a/chrome/browser/ui/views/autofill/popup/popup_row_view.cc b/chrome/browser/ui/views/autofill/popup/popup_row_view.cc
index 86187044..127be88 100644
--- a/chrome/browser/ui/views/autofill/popup/popup_row_view.cc
+++ b/chrome/browser/ui/views/autofill/popup/popup_row_view.cc
@@ -340,7 +340,7 @@
     content_view_->UpdateStyle(/*selected=*/false);
     content_view_->GetViewAccessibility().OverrideIsSelected(false);
     if (controller_) {
-      controller_->SelectSuggestion(std::nullopt);
+      controller_->UnselectSuggestion();
     }
   }
 
diff --git a/chrome/browser/ui/views/autofill/popup/popup_row_view_unittest.cc b/chrome/browser/ui/views/autofill/popup/popup_row_view_unittest.cc
index b67e2b8d..1fa55d3 100644
--- a/chrome/browser/ui/views/autofill/popup/popup_row_view_unittest.cc
+++ b/chrome/browser/ui/views/autofill/popup/popup_row_view_unittest.cc
@@ -278,7 +278,7 @@
   ASSERT_TRUE(row_view().GetExpandChildSuggestionsView());
   ASSERT_FALSE(row_view().GetSelectedCell().has_value());
 
-  EXPECT_CALL(controller(), SelectSuggestion(std::optional<size_t>(0)));
+  EXPECT_CALL(controller(), SelectSuggestion(0u));
   row_view().SetSelectedCell(CellType::kContent);
 
   // No selection triggering if trying to set already selected content.
@@ -286,10 +286,10 @@
   row_view().SetSelectedCell(CellType::kContent);
 
   // Deselection of selected content.
-  EXPECT_CALL(controller(), SelectSuggestion(std::optional<size_t>()));
+  EXPECT_CALL(controller(), UnselectSuggestion);
   row_view().SetSelectedCell(CellType::kControl);
 
-  EXPECT_CALL(controller(), SelectSuggestion(std::optional<size_t>(0)));
+  EXPECT_CALL(controller(), SelectSuggestion(0u));
   row_view().SetSelectedCell(CellType::kContent);
 }
 
diff --git a/chrome/browser/ui/views/autofill/popup/popup_row_with_button_view.cc b/chrome/browser/ui/views/autofill/popup/popup_row_with_button_view.cc
index 5994bc5e..f4e41563 100644
--- a/chrome/browser/ui/views/autofill/popup/popup_row_with_button_view.cc
+++ b/chrome/browser/ui/views/autofill/popup/popup_row_with_button_view.cc
@@ -271,11 +271,15 @@
     return;
   }
 
+  if (!controller()) {
+    return;
+  }
+
   focused_part_ = part;
-  if (controller()) {
-    controller()->SelectSuggestion(focused_part_ == RowWithButtonPart::kContent
-                                       ? std::optional<size_t>(line_number())
-                                       : std::nullopt);
+  if (focused_part_ == RowWithButtonPart::kContent) {
+    controller()->SelectSuggestion(line_number());
+  } else {
+    controller()->UnselectSuggestion();
   }
 }
 
diff --git a/chrome/browser/ui/views/autofill/popup/popup_row_with_button_view_unittest.cc b/chrome/browser/ui/views/autofill/popup/popup_row_with_button_view_unittest.cc
index 5c23056b..59876122 100644
--- a/chrome/browser/ui/views/autofill/popup/popup_row_with_button_view_unittest.cc
+++ b/chrome/browser/ui/views/autofill/popup/popup_row_with_button_view_unittest.cc
@@ -152,12 +152,12 @@
   button->parent()->SetBoundsRect(gfx::Rect(0, 0, 30, 30));
 
   // The button becomes focused if it is hovered.
-  EXPECT_CALL(controller(), SelectSuggestion(std::optional<size_t>()));
+  EXPECT_CALL(controller(), UnselectSuggestion);
   generator().MoveMouseTo(button->GetBoundsInScreen().CenterPoint());
   EXPECT_TRUE(view().GetButtonFocusedForTest());
 
   // Selected is true if hovering the label when the button state changes.
-  EXPECT_CALL(controller(), SelectSuggestion(std::optional<size_t>(0)));
+  EXPECT_CALL(controller(), SelectSuggestion(0u));
   generator().MoveMouseTo(label->GetBoundsInScreen().CenterPoint());
   EXPECT_FALSE(view().GetButtonFocusedForTest());
 }
diff --git a/chrome/browser/ui/views/autofill/popup/popup_view_utils.cc b/chrome/browser/ui/views/autofill/popup/popup_view_utils.cc
index 09d00af..9b1007bc 100644
--- a/chrome/browser/ui/views/autofill/popup/popup_view_utils.cc
+++ b/chrome/browser/ui/views/autofill/popup/popup_view_utils.cc
@@ -560,7 +560,6 @@
     case PopupItemId::kFillFullEmail:
     case PopupItemId::kFillFullPhoneNumber:
     case PopupItemId::kAddressEntryNotSelectable:
-    case PopupItemId::kPaymentsEntryNotSelectable:
     case PopupItemId::kGeneratePasswordEntry:
     case PopupItemId::kIbanEntry:
     case PopupItemId::kInsecureContextPaymentDisabledMessage:
@@ -612,7 +611,6 @@
     case PopupItemId::kDevtoolsTestAddressEntry:
     case PopupItemId::kDevtoolsTestAddresses:
     case PopupItemId::kAddressEntryNotSelectable:
-    case PopupItemId::kPaymentsEntryNotSelectable:
     case PopupItemId::kFillExistingPlusAddress:
     case PopupItemId::kFillFullAddress:
     case PopupItemId::kFillFullName:
@@ -644,7 +642,7 @@
     case PopupItemId::kFillFullEmail:
     case PopupItemId::kFillFullPhoneNumber:
     case PopupItemId::kAddressEntryNotSelectable:
-    case PopupItemId::kPaymentsEntryNotSelectable:
+    case PopupItemId::kCreditCardEntry:
       return true;
     case PopupItemId::kAccountStoragePasswordEntry:
     case PopupItemId::kAccountStorageUsernameEntry:
@@ -654,7 +652,6 @@
     case PopupItemId::kClearForm:
     case PopupItemId::kCompose:
     case PopupItemId::kCreateNewPlusAddress:
-    case PopupItemId::kCreditCardEntry:
     case PopupItemId::kDatalistEntry:
     case PopupItemId::kDevtoolsTestAddressEntry:
     case PopupItemId::kDeleteAddressProfile:
diff --git a/chrome/browser/ui/views/autofill/popup/popup_view_views_unittest.cc b/chrome/browser/ui/views/autofill/popup/popup_view_views_unittest.cc
index 70ebad5..bb6596f 100644
--- a/chrome/browser/ui/views/autofill/popup/popup_view_views_unittest.cc
+++ b/chrome/browser/ui/views/autofill/popup/popup_view_views_unittest.cc
@@ -427,12 +427,12 @@
   CreateAndShowView({PopupItemId::kPasswordEntry});
 
   // Tap down (initiated by generating a touch press) will select an element.
-  EXPECT_CALL(controller(), SelectSuggestion(std::optional<size_t>(0u)));
+  EXPECT_CALL(controller(), SelectSuggestion(0));
   generator().PressTouch(
       GetPopupRowViewAt(0).GetBoundsInScreen().CenterPoint());
 
   // Canceling gesture clears any selection.
-  EXPECT_CALL(controller(), SelectSuggestion(std::optional<size_t>()));
+  EXPECT_CALL(controller(), UnselectSuggestion);
   generator().CancelTouch();
 }
 #endif  // !BUILDFLAG(IS_MAC)
diff --git a/chrome/browser/ui/views/compose/compose_dialog_view.cc b/chrome/browser/ui/views/compose/compose_dialog_view.cc
index 5ef86f7..5cf7d78 100644
--- a/chrome/browser/ui/views/compose/compose_dialog_view.cc
+++ b/chrome/browser/ui/views/compose/compose_dialog_view.cc
@@ -88,6 +88,12 @@
   return best_location;
 }
 
+bool ComposeDialogView::HandleContextMenu(
+    content::RenderFrameHost& render_frame_host,
+    const content::ContextMenuParams& params) {
+  return false;
+}
+
 base::WeakPtr<ComposeDialogView> ComposeDialogView::GetWeakPtr() {
   return weak_ptr_factory_.GetWeakPtr();
 }
diff --git a/chrome/browser/ui/views/compose/compose_dialog_view.h b/chrome/browser/ui/views/compose/compose_dialog_view.h
index 5f598b1..cb8b1f6 100644
--- a/chrome/browser/ui/views/compose/compose_dialog_view.h
+++ b/chrome/browser/ui/views/compose/compose_dialog_view.h
@@ -28,6 +28,8 @@
   gfx::Rect GetBubbleBounds() override;
   void OnBeforeBubbleWidgetInit(views::Widget::InitParams* params,
                                 views::Widget* widget) const override;
+  bool HandleContextMenu(content::RenderFrameHost& render_frame_host,
+                         const content::ContextMenuParams& params) override;
 
   BubbleContentsWrapperT<ComposeUI>* bubble_wrapper() {
     return bubble_wrapper_.get();
diff --git a/chrome/browser/ui/views/default_link_capturing_interactive_uitest.cc b/chrome/browser/ui/views/default_link_capturing_interactive_uitest.cc
index 5920e06..2e68a45 100644
--- a/chrome/browser/ui/views/default_link_capturing_interactive_uitest.cc
+++ b/chrome/browser/ui/views/default_link_capturing_interactive_uitest.cc
@@ -12,11 +12,8 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/ui/intent_picker_tab_helper.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
-#include "chrome/browser/ui/views/frame/toolbar_button_provider.h"
-#include "chrome/browser/ui/views/intent_picker_bubble_view.h"
-#include "chrome/browser/ui/views/location_bar/intent_chip_button.h"
+#include "chrome/browser/ui/views/user_education/browser_feature_promo_controller.h"
 #include "chrome/browser/ui/views/web_apps/web_app_link_capturing_test_utils.h"
 #include "chrome/browser/ui/web_applications/app_browser_controller.h"
 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
@@ -37,8 +34,8 @@
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/events/event.h"
+#include "ui/events/types/event_type.h"
 #include "ui/gfx/geometry/point.h"
-#include "ui/views/controls/button/button.h"
 #include "ui/views/interaction/interaction_test_util_views.h"
 #include "ui/views/test/button_test_api.h"
 #include "ui/views/widget/any_widget_observer.h"
@@ -63,93 +60,6 @@
     ASSERT_TRUE(embedded_test_server()->Start());
   }
 
-  content::WebContents* GetWebContents() {
-    return browser()->tab_strip_model()->GetActiveWebContents();
-  }
-
-  IntentChipButton* GetIntentPickerIcon() {
-    return BrowserView::GetBrowserViewForBrowser(browser())
-        ->toolbar_button_provider()
-        ->GetIntentChipButton();
-  }
-
-  IntentPickerBubbleView* intent_picker_bubble() {
-    return IntentPickerBubbleView::intent_picker_bubble();
-  }
-
-  testing::AssertionResult AwaitIntentPickerTabHelperIconUpdateComplete() {
-    base::test::TestFuture<void> future;
-    auto* tab_helper = IntentPickerTabHelper::FromWebContents(GetWebContents());
-    tab_helper->SetIconUpdateCallbackForTesting(  // IN-TEST
-        future.GetCallback(), /*include_latest_navigation=*/true);
-    if (!future.Wait()) {
-      return testing::AssertionFailure()
-             << "Intent picker app did not resolve an applicable app.";
-    }
-    return testing::AssertionSuccess();
-  }
-
-  testing::AssertionResult WaitForIntentPickerToShow() {
-    auto result = AwaitIntentPickerTabHelperIconUpdateComplete();
-    if (!result) {
-      return result;
-    }
-    IntentChipButton* intent_picker_icon = GetIntentPickerIcon();
-    if (!intent_picker_icon) {
-      return testing::AssertionFailure()
-             << "Intent picker icon does not exist.";
-    }
-
-    if (!intent_picker_icon->GetVisible()) {
-      web_app::IntentChipVisibilityObserver intent_chip_visibility_observer(
-          intent_picker_icon);
-      intent_chip_visibility_observer.WaitForChipToBeVisible();
-      if (!intent_picker_icon->GetVisible()) {
-        return testing::AssertionFailure()
-               << "Intent picker icon never became visible.";
-      }
-    }
-
-    return testing::AssertionSuccess();
-  }
-
-  testing::AssertionResult ClickIntentPickerChip() {
-    auto result = WaitForIntentPickerToShow();
-    if (!result) {
-      return result;
-    }
-
-    views::test::ButtonTestApi test_api(GetIntentPickerIcon());
-    test_api.NotifyClick(ui::MouseEvent(
-        ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), base::TimeTicks(),
-        ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
-    return testing::AssertionSuccess();
-  }
-
-  testing::AssertionResult ClickIntentPickerAndWaitForBubble() {
-    auto result = WaitForIntentPickerToShow();
-    if (!result) {
-      return result;
-    }
-
-    views::NamedWidgetShownWaiter intent_picker_bubble_shown(
-        views::test::AnyWidgetTestPasskey{},
-        IntentPickerBubbleView::kViewClassName);
-    views::test::ButtonTestApi test_api(GetIntentPickerIcon());
-    test_api.NotifyClick(ui::MouseEvent(
-        ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), base::TimeTicks(),
-        ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
-
-    if (!intent_picker_bubble_shown.WaitIfNeededAndGet()) {
-      return testing::AssertionFailure()
-             << "Intent picker bubble did not appear after click.";
-    }
-
-    EXPECT_NE(intent_picker_bubble(), nullptr)
-        << "intent picker not initialized";
-    return testing::AssertionSuccess();
-  }
-
   size_t GetItemContainerSize(IntentPickerBubbleView* bubble) {
     return bubble->GetViewByID(IntentPickerBubbleView::ViewId::kItemContainer)
         ->children()
@@ -182,17 +92,6 @@
     return {outer_app_id, inner_app_id};
   }
 
-  views::Button* GetIntentPickerButtonAtIndex(size_t index) {
-    EXPECT_NE(intent_picker_bubble(), nullptr)
-        << " intent picker bubble not initialized";
-    auto children =
-        intent_picker_bubble()
-            ->GetViewByID(IntentPickerBubbleView::ViewId::kItemContainer)
-            ->children();
-    EXPECT_LE(index, children.size());
-    return static_cast<views::Button*>(children[index]);
-  }
-
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
 };
@@ -202,13 +101,13 @@
   const auto [outer_app_id, inner_app_id] = InstallOuterAppAndInnerApp();
 
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetNestedPageUrl()));
-  EXPECT_TRUE(ClickIntentPickerAndWaitForBubble());
+  EXPECT_TRUE(web_app::ClickIntentPickerAndWaitForBubble(browser()));
 
   base::UserActionTester user_action_tester;
   // The app list is currently not deterministically ordered, so find the
   // correct item and select that.
   const auto& app_infos =
-      intent_picker_bubble()->app_info_for_testing();  // IN-TEST
+      web_app::intent_picker_bubble()->app_info_for_testing();  // IN-TEST
   auto it = base::ranges::find(app_infos, outer_app_id,
                                &apps::IntentPickerAppInfo::launch_name);
   ASSERT_NE(it, app_infos.end());
@@ -216,11 +115,12 @@
 
   ui_test_utils::BrowserChangeObserver browser_added_waiter(
       nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
-  views::test::ButtonTestApi test_api(GetIntentPickerButtonAtIndex(index));
+  views::test::ButtonTestApi test_api(
+      web_app::GetIntentPickerButtonAtIndex(index));
   test_api.NotifyClick(ui::MouseEvent(
       ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), base::TimeTicks(),
       ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
-  intent_picker_bubble()->AcceptDialog();
+  web_app::intent_picker_bubble()->AcceptDialog();
 
   EXPECT_EQ(
       1, user_action_tester.GetActionCount("IntentPickerViewAcceptLaunchApp"));
@@ -237,8 +137,8 @@
 
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetNestedPageUrl()));
   base::UserActionTester user_action_tester;
-  EXPECT_TRUE(ClickIntentPickerAndWaitForBubble());
-  intent_picker_bubble()->CancelDialog();
+  EXPECT_TRUE(web_app::ClickIntentPickerAndWaitForBubble(browser()));
+  web_app::intent_picker_bubble()->CancelDialog();
 
   EXPECT_EQ(1, user_action_tester.GetActionCount(
                    "IntentPickerViewClosedStayInChrome"));
@@ -252,7 +152,7 @@
 
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetNestedPageUrl()));
   base::UserActionTester user_action_tester;
-  EXPECT_TRUE(ClickIntentPickerAndWaitForBubble());
+  EXPECT_TRUE(web_app::ClickIntentPickerAndWaitForBubble(browser()));
   // Opening a new tab should ignore the current intent picker view.
   chrome::NewTab(browser());
 
@@ -278,8 +178,8 @@
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url1));
 
   // Verify that no icon was shown.
-  EXPECT_TRUE(AwaitIntentPickerTabHelperIconUpdateComplete());
-  ASSERT_FALSE(GetIntentPickerIcon()->GetVisible());
+  EXPECT_TRUE(web_app::AwaitIntentPickerTabHelperIconUpdateComplete(browser()));
+  ASSERT_FALSE(web_app::GetIntentPickerIcon(browser())->GetVisible());
 
   // Load a different page while simulating it having a native app.
   apps::OverrideMacAppForUrlForTesting(true, kFinderAppPath);
@@ -287,11 +187,12 @@
 
   // Verify intent picker chip shows up, click on it, and wait for the bubble to
   // be populated
-  EXPECT_TRUE(ClickIntentPickerAndWaitForBubble());
-  EXPECT_TRUE(intent_picker_bubble()->GetVisible());
+  EXPECT_TRUE(web_app::ClickIntentPickerAndWaitForBubble(browser()));
+  EXPECT_TRUE(web_app::intent_picker_bubble()->GetVisible());
 
-  EXPECT_EQ(1U, GetItemContainerSize(intent_picker_bubble()));
-  auto& app_info = intent_picker_bubble()->app_info_for_testing();  // IN-TEST
+  EXPECT_EQ(1U, GetItemContainerSize(web_app::intent_picker_bubble()));
+  auto& app_info =
+      web_app::intent_picker_bubble()->app_info_for_testing();  // IN-TEST
   ASSERT_EQ(1U, app_info.size());
   EXPECT_EQ(kFinderAppPath, app_info[0].launch_name);
   EXPECT_EQ(kFinderAppName, app_info[0].display_name);
@@ -301,7 +202,7 @@
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url1));
 
   // Verify that the icon was hidden.
-  ASSERT_FALSE(GetIntentPickerIcon()->GetVisible());
+  ASSERT_FALSE(web_app::GetIntentPickerIcon(browser())->GetVisible());
 }
 #endif  // BUILDFLAG(IS_MAC)
 
@@ -422,7 +323,7 @@
   ui_test_utils::BrowserChangeObserver browser_added_waiter(
       nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
 
-  ASSERT_TRUE(ClickIntentPickerChip());
+  ASSERT_TRUE(web_app::ClickIntentPickerChip(browser()));
   Browser* app_browser = browser_added_waiter.Wait();
   ASSERT_TRUE(app_browser);
   EXPECT_TRUE(web_app::AppBrowserController::IsForWebApp(app_browser, app_id));
diff --git a/chrome/browser/ui/views/enable_link_capturing_infobar_browsertest.cc b/chrome/browser/ui/views/enable_link_capturing_infobar_browsertest.cc
index 18d4c6d..c36fd8e3 100644
--- a/chrome/browser/ui/views/enable_link_capturing_infobar_browsertest.cc
+++ b/chrome/browser/ui/views/enable_link_capturing_infobar_browsertest.cc
@@ -14,11 +14,6 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
-#include "chrome/browser/ui/intent_picker_tab_helper.h"
-#include "chrome/browser/ui/views/frame/browser_view.h"
-#include "chrome/browser/ui/views/frame/toolbar_button_provider.h"
-#include "chrome/browser/ui/views/intent_picker_bubble_view.h"
-#include "chrome/browser/ui/views/location_bar/intent_chip_button.h"
 #include "chrome/browser/ui/views/web_apps/web_app_link_capturing_test_utils.h"
 #include "chrome/browser/ui/web_applications/app_browser_controller.h"
 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
@@ -62,12 +57,6 @@
 
   bool LinkCapturingEnabledByDefault() { return GetParam(); }
 
-  IntentChipButton* GetIntentPickerIcon() {
-    return BrowserView::GetBrowserViewForBrowser(browser())
-        ->toolbar_button_provider()
-        ->GetIntentChipButton();
-  }
-
   // Returns [app_id, in_scope_url]
   std::tuple<webapps::AppId, GURL> InstallTestApp() {
     GURL start_url = embedded_test_server()->GetURL("/web_apps/basic.html");
@@ -129,88 +118,6 @@
     ASSERT_TRUE(preference_set.Wait());
   }
 
-  testing::AssertionResult WaitForIntentPickerToShow() {
-    base::test::TestFuture<void> future;
-    auto* tab_helper =
-        IntentPickerTabHelper::FromWebContents(GetActiveWebContents(browser()));
-    tab_helper->SetIconUpdateCallbackForTesting(
-        future.GetCallback(), /*include_latest_navigation=*/true);
-    if (!future.Wait()) {
-      return testing::AssertionFailure()
-             << "Intent picker app did not resolve an applicable app.";
-    }
-
-    IntentChipButton* intent_picker_icon = GetIntentPickerIcon();
-    if (!intent_picker_icon) {
-      return testing::AssertionFailure()
-             << "Intent picker icon does not exist.";
-    }
-
-    if (!intent_picker_icon->GetVisible()) {
-      web_app::IntentChipVisibilityObserver intent_chip_visibility_observer(
-          intent_picker_icon);
-      intent_chip_visibility_observer.WaitForChipToBeVisible();
-      if (!intent_picker_icon->GetVisible()) {
-        return testing::AssertionFailure()
-               << "Intent picker icon never became visible.";
-      }
-    }
-    EXPECT_TRUE(intent_picker_icon->GetVisible());
-
-    return testing::AssertionSuccess();
-  }
-
-  testing::AssertionResult ClickIntentPickerChip() {
-    testing::AssertionResult intent_picker_icon_shown =
-        WaitForIntentPickerToShow();
-    if (!intent_picker_icon_shown) {
-      return intent_picker_icon_shown;
-    }
-
-    views::test::ButtonTestApi test_api(GetIntentPickerIcon());
-    test_api.NotifyClick(ui::MouseEvent(
-        ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), base::TimeTicks(),
-        ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
-    return testing::AssertionSuccess();
-  }
-
-  testing::AssertionResult ClickIntentPickerAndWaitForBubble() {
-    testing::AssertionResult intent_picker_icon_shown =
-        WaitForIntentPickerToShow();
-    if (!intent_picker_icon_shown) {
-      return intent_picker_icon_shown;
-    }
-
-    views::NamedWidgetShownWaiter intent_picker_bubble_shown(
-        views::test::AnyWidgetTestPasskey{},
-        IntentPickerBubbleView::kViewClassName);
-    views::test::ButtonTestApi test_api(GetIntentPickerIcon());
-    test_api.NotifyClick(ui::MouseEvent(
-        ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), base::TimeTicks(),
-        ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
-
-    if (!intent_picker_bubble_shown.WaitIfNeededAndGet()) {
-      return testing::AssertionFailure()
-             << "Intent picker bubble did not appear after click.";
-    }
-    CHECK(intent_picker_bubble());
-    return testing::AssertionSuccess();
-  }
-
-  IntentPickerBubbleView* intent_picker_bubble() {
-    return IntentPickerBubbleView::intent_picker_bubble();
-  }
-
-  views::Button* GetIntentPickerButtonAtIndex(size_t index) {
-    CHECK(intent_picker_bubble());
-    auto children =
-        intent_picker_bubble()
-            ->GetViewByID(IntentPickerBubbleView::ViewId::kItemContainer)
-            ->children();
-    CHECK_LT(index, children.size());
-    return static_cast<views::Button*>(children[index]);
-  }
-
  private:
   base::test::ScopedFeatureList feature_list_;
 };
@@ -230,7 +137,7 @@
 
   ui_test_utils::BrowserChangeObserver browser_added_waiter(
       nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
-  ASSERT_TRUE(ClickIntentPickerChip());
+  ASSERT_TRUE(web_app::ClickIntentPickerChip(browser()));
   Browser* app_browser = browser_added_waiter.Wait();
   ASSERT_TRUE(app_browser);
 
@@ -254,7 +161,7 @@
   {
     ui_test_utils::BrowserChangeObserver browser_added_waiter(
         nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
-    ASSERT_TRUE(ClickIntentPickerChip());
+    ASSERT_TRUE(web_app::ClickIntentPickerChip(browser()));
     app_browser = browser_added_waiter.Wait();
     ASSERT_TRUE(app_browser);
   }
@@ -296,7 +203,7 @@
   // app is also set to capture links by default, the link should open in the
   // PWA automatically on clicking the intent chip without going through the
   // intent picker bubble.
-  ASSERT_TRUE(ClickIntentPickerChip());
+  ASSERT_TRUE(web_app::ClickIntentPickerChip(browser()));
   Browser* app_browser = browser_added_waiter.Wait();
   ASSERT_TRUE(app_browser);
 
@@ -318,7 +225,7 @@
 
   ui_test_utils::BrowserChangeObserver browser_added_waiter(
       nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
-  ASSERT_TRUE(ClickIntentPickerChip());
+  ASSERT_TRUE(web_app::ClickIntentPickerChip(browser()));
   Browser* app_browser = browser_added_waiter.Wait();
   ASSERT_TRUE(app_browser);
 
@@ -356,7 +263,7 @@
 
   ui_test_utils::BrowserChangeObserver browser_added_waiter(
       nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
-  ASSERT_TRUE(ClickIntentPickerChip());
+  ASSERT_TRUE(web_app::ClickIntentPickerChip(browser()));
   Browser* app_browser = browser_added_waiter.Wait();
   ASSERT_TRUE(app_browser);
 
@@ -392,7 +299,7 @@
   {
     ui_test_utils::BrowserChangeObserver browser_added_waiter(
         nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
-    ASSERT_TRUE(ClickIntentPickerChip());
+    ASSERT_TRUE(web_app::ClickIntentPickerChip(browser()));
     app_browser = browser_added_waiter.Wait();
     ASSERT_TRUE(app_browser);
   }
@@ -438,7 +345,7 @@
 
   ui_test_utils::BrowserChangeObserver browser_added_waiter(
       nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
-  ASSERT_TRUE(ClickIntentPickerChip());
+  ASSERT_TRUE(web_app::ClickIntentPickerChip(browser()));
   Browser* app_browser = browser_added_waiter.Wait();
   ASSERT_TRUE(app_browser);
 
@@ -475,7 +382,7 @@
 
     ui_test_utils::BrowserChangeObserver browser_added_waiter(
         nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
-    ASSERT_TRUE(ClickIntentPickerChip());
+    ASSERT_TRUE(web_app::ClickIntentPickerChip(browser()));
     Browser* app_browser = browser_added_waiter.Wait();
     ASSERT_TRUE(app_browser);
 
@@ -503,7 +410,7 @@
 
   ui_test_utils::BrowserChangeObserver browser_added_waiter(
       nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
-  ASSERT_TRUE(ClickIntentPickerChip());
+  ASSERT_TRUE(web_app::ClickIntentPickerChip(browser()));
   Browser* app_browser = browser_added_waiter.Wait();
   ASSERT_TRUE(app_browser);
 
@@ -525,11 +432,12 @@
   }
 
   NavigateViaLinkClick(browser(), inner_app_scoped_url);
-  EXPECT_TRUE(ClickIntentPickerAndWaitForBubble());
+  EXPECT_TRUE(web_app::ClickIntentPickerAndWaitForBubble(browser()));
 
   // The app list is currently not deterministically ordered, so find the
   // correct item and select that.
-  const auto& app_infos = intent_picker_bubble()->app_info_for_testing();
+  const auto& app_infos =
+      web_app::intent_picker_bubble()->app_info_for_testing();
   auto it = base::ranges::find(app_infos, outer_app_id,
                                &apps::IntentPickerAppInfo::launch_name);
   ASSERT_NE(it, app_infos.end());
@@ -537,11 +445,12 @@
 
   ui_test_utils::BrowserChangeObserver browser_added_waiter(
       nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
-  views::test::ButtonTestApi test_api(GetIntentPickerButtonAtIndex(index));
+  views::test::ButtonTestApi test_api(
+      web_app::GetIntentPickerButtonAtIndex(index));
   test_api.NotifyClick(ui::MouseEvent(
       ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), base::TimeTicks(),
       ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
-  intent_picker_bubble()->AcceptDialog();
+  web_app::intent_picker_bubble()->AcceptDialog();
 
   Browser* app_browser = browser_added_waiter.Wait();
   ASSERT_TRUE(app_browser);
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 536ff3d93..2af30a6 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -2589,8 +2589,6 @@
 }
 
 void BrowserView::SynchronizeRenderWidgetHostVisualPropertiesForMainFrame() {
-// TODO(crbug.com/1503145): Investigate and fix on MacOS.
-#if !BUILDFLAG(IS_MAC)
   content::WebContents* web_contents = GetActiveWebContents();
   if (!web_contents || !web_contents->GetPrimaryMainFrame()) {
     return;
@@ -2600,7 +2598,6 @@
           web_contents->GetPrimaryMainFrame()->GetRenderWidgetHost()) {
     render_widget_host->SynchronizeVisualProperties();
   }
-#endif
 }
 
 void BrowserView::OnWidgetSizeConstraintsChanged(views::Widget* widget) {
diff --git a/chrome/browser/ui/views/location_bar/content_setting_image_view.cc b/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
index 35560ad..f8315137 100644
--- a/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
+++ b/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/views/location_bar/content_setting_image_view.h"
 
+#include <cstddef>
 #include <optional>
 #include <string>
 #include <utility>
@@ -78,6 +79,10 @@
 
 DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(ContentSettingImageView,
                                       kMediaActivityIndicatorElementId);
+DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(ContentSettingImageView,
+                                      kMidiActivityIndicatorElementId);
+DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(ContentSettingImageView,
+                                      kMidiSysexActivityIndicatorElementId);
 
 ContentSettingImageView::ContentSettingImageView(
     std::unique_ptr<ContentSettingImageModel> image_model,
@@ -193,9 +198,22 @@
 
   content_setting_image_model_->SetAnimationHasRun(web_contents);
 
-  if (content_setting_image_model_->image_type() ==
-      ContentSettingImageModel::ImageType::MEDIASTREAM) {
-    SetProperty(views::kElementIdentifierKey, kMediaActivityIndicatorElementId);
+  std::optional<ui::ElementIdentifier> element_identifier;
+  switch (content_setting_image_model_->image_type()) {
+    case ContentSettingImageModel::ImageType::MEDIASTREAM:
+      element_identifier = kMediaActivityIndicatorElementId;
+      break;
+    case ContentSettingImageModel::ImageType::MIDI:
+      element_identifier = kMidiActivityIndicatorElementId;
+      break;
+    case ContentSettingImageModel::ImageType::MIDI_SYSEX:
+      element_identifier = kMidiSysexActivityIndicatorElementId;
+      break;
+    default:
+      break;
+  }
+  if (element_identifier) {
+    SetProperty(views::kElementIdentifierKey, *element_identifier);
   }
 }
 
diff --git a/chrome/browser/ui/views/location_bar/content_setting_image_view.h b/chrome/browser/ui/views/location_bar/content_setting_image_view.h
index 487709c..3848c259 100644
--- a/chrome/browser/ui/views/location_bar/content_setting_image_view.h
+++ b/chrome/browser/ui/views/location_bar/content_setting_image_view.h
@@ -40,6 +40,8 @@
  public:
   METADATA_HEADER(ContentSettingImageView);
   DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kMediaActivityIndicatorElementId);
+  DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kMidiActivityIndicatorElementId);
+  DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kMidiSysexActivityIndicatorElementId);
   class Delegate {
    public:
     // Delegate should return true if the content setting icon should be hidden.
diff --git a/chrome/browser/ui/views/performance_controls/memory_saver_chip_view_unittest.cc b/chrome/browser/ui/views/performance_controls/memory_saver_chip_view_unittest.cc
index 92458ff..316e07cb 100644
--- a/chrome/browser/ui/views/performance_controls/memory_saver_chip_view_unittest.cc
+++ b/chrome/browser/ui/views/performance_controls/memory_saver_chip_view_unittest.cc
@@ -72,7 +72,7 @@
     AddNewTab(kMemorySavingsKilobytes,
               ::mojom::LifecycleUnitDiscardReason::PROACTIVE);
 
-    SetHighEfficiencyModeEnabled(true);
+    SetMemorySaverModeEnabled(true);
   }
 
   // Creates a new tab at index 0 that would report the given memory savings and
@@ -104,7 +104,7 @@
         ->UpdateAll();
   }
 
-  void SetHighEfficiencyModeEnabled(bool enabled) {
+  void SetMemorySaverModeEnabled(bool enabled) {
     performance_manager::user_tuning::UserPerformanceTuningManager::
         GetInstance()
             ->SetMemorySaverModeEnabled(enabled);
@@ -158,7 +158,7 @@
 // If a discard is triggered when the user doesn't have memory saver mode
 // enabled, we don't show the chip.
 TEST_F(MemorySaverChipViewTest, ShouldNotShowWhenPrefIsFalse) {
-  SetHighEfficiencyModeEnabled(false);
+  SetMemorySaverModeEnabled(false);
   SetTabDiscardState(0, true);
 
   PageActionIconView* view = GetPageActionIconView();
@@ -270,7 +270,7 @@
     AddNewTab(kMemorySavingsKilobytes,
               ::mojom::LifecycleUnitDiscardReason::PROACTIVE);
 
-    SetHighEfficiencyModeEnabled(true);
+    SetMemorySaverModeEnabled(true);
   }
 
  private:
@@ -369,7 +369,7 @@
     AddNewTab(kMemorySavingsKilobytes,
               ::mojom::LifecycleUnitDiscardReason::PROACTIVE);
 
-    SetHighEfficiencyModeEnabled(true);
+    SetMemorySaverModeEnabled(true);
   }
 
  private:
diff --git a/chrome/browser/ui/views/performance_controls/memory_saver_interactive_ui_test.cc b/chrome/browser/ui/views/performance_controls/memory_saver_interactive_ui_test.cc
index 6442aeb5..4be371b 100644
--- a/chrome/browser/ui/views/performance_controls/memory_saver_interactive_ui_test.cc
+++ b/chrome/browser/ui/views/performance_controls/memory_saver_interactive_ui_test.cc
@@ -517,16 +517,8 @@
       WaitForHide(MemorySaverBubbleView::kMemorySaverDialogBodyElementId));
 }
 
-// TODO(crbug.com/1416372): Re-enable this test
-#if BUILDFLAG(IS_WIN)
-#define MAYBE_BubbleCorrectlyReportingMemorySaved \
-  DISABLED_BubbleCorrectlyReportingMemorySaved
-#else
-#define MAYBE_BubbleCorrectlyReportingMemorySaved \
-  BubbleCorrectlyReportingMemorySaved
-#endif
 IN_PROC_BROWSER_TEST_F(MemorySaverChipInteractiveTest,
-                       MAYBE_BubbleCorrectlyReportingMemorySaved) {
+                       BubbleCorrectlyReportingMemorySaved) {
   RunTestSequence(
       InstrumentTab(kFirstTabContents, 0),
       NavigateWebContents(kFirstTabContents, GetURL("/title1.html")),
diff --git a/chrome/browser/ui/views/permissions/midi_permissions_flow_interactive_uitest.cc b/chrome/browser/ui/views/permissions/midi_permissions_flow_interactive_uitest.cc
index 23da670..607bb49 100644
--- a/chrome/browser/ui/views/permissions/midi_permissions_flow_interactive_uitest.cc
+++ b/chrome/browser/ui/views/permissions/midi_permissions_flow_interactive_uitest.cc
@@ -111,6 +111,7 @@
           l10n_util::GetStringFUTF16(
               IDS_PERMISSIONS_BUBBLE_PROMPT_ACCESSIBLE_TITLE_ONE_PERM, u"",
               l10n_util::GetStringUTF16(IDS_MIDI_PERMISSION_FRAGMENT))));
+  // TODO(b/315345075): Add a check for the strings displayed in the prompt.
 }
 
 // Display MIDI permission state in page info when denied.
@@ -142,6 +143,7 @@
             EXPECT_TRUE(includes_midi);
             EXPECT_FALSE(includes_midi_sysex);
           })));
+  // TODO(b/315345075): Add a check for the state of MIDI toggle.
 }
 
 // Display MIDI permission state in page info when allowed.
@@ -173,4 +175,34 @@
             EXPECT_TRUE(includes_midi);
             EXPECT_FALSE(includes_midi_sysex);
           })));
+  // TODO(b/315345075): Add a check for the state of MIDI toggle.
+}
+
+// TODO(b/315345075): Add a test for the behavior of the MIDI toggle in page
+// info.
+
+// Display in-use indicator of MIDI when blocked.
+IN_PROC_BROWSER_TEST_F(MidiPermissionsFlowInteractiveUITest,
+                       BlockedMidiPermissionIndicator) {
+  RunTestSequenceInContext(
+      context(), NavigateAndRequestMidi(),
+      PressButton(PermissionPromptBubbleBaseView::kBlockButtonElementId),
+      WaitForHide(PermissionPromptBubbleBaseView::kMainViewId),
+      WaitForShow(ContentSettingImageView::kMidiActivityIndicatorElementId));
+  // TODO(b/315345075): Add a check to ensure the off MIDI icon is displayed.
+  // TODO(b/315345075): Add a check for the strings displayed in the bubble.
+  // TODO(b/315345075): Add a check to ensure only one MIDI icon is displayed.
+}
+
+// Display in-use indicator of MIDI when allowed.
+IN_PROC_BROWSER_TEST_F(MidiPermissionsFlowInteractiveUITest,
+                       AllowedMidiPermissionIndicator) {
+  RunTestSequenceInContext(
+      context(), NavigateAndRequestMidi(),
+      PressButton(PermissionPromptBubbleBaseView::kAllowButtonElementId),
+      WaitForHide(PermissionPromptBubbleBaseView::kMainViewId),
+      WaitForShow(ContentSettingImageView::kMidiActivityIndicatorElementId));
+  // TODO(b/315345075): Add a check to ensure the on MIDI icon is displayed.
+  // TODO(b/315345075): Add a check for the strings displayed in the bubble.
+  // TODO(b/315345075): Add a check to ensure only one MIDI icon is displayed.
 }
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc b/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc
index 5d10b46..0329b45 100644
--- a/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc
+++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc
@@ -73,7 +73,8 @@
 
 PermissionPromptBubbleBaseView::~PermissionPromptBubbleBaseView() = default;
 
-void PermissionPromptBubbleBaseView::CreatePermissionButtons() {
+void PermissionPromptBubbleBaseView::CreatePermissionButtons(
+    const std::u16string& allow_always_text) {
   if (is_one_time_permission_) {
     SetButtons(ui::DIALOG_BUTTON_NONE);
 
@@ -95,7 +96,7 @@
                                 FilterUnintenedEventsAndRunCallbacks,
                             base::Unretained(this),
                             GetViewId(PermissionDialogButton::kAccept)),
-        l10n_util::GetStringUTF16(IDS_PERMISSION_ALLOW_EVERY_VISIT));
+        allow_always_text);
     allow_always_button->SetProperty(views::kElementIdentifierKey,
                                      kAllowButtonElementId);
     allow_always_button->SetID(GetViewId(PermissionDialogButton::kAccept));
@@ -299,6 +300,21 @@
   return true;
 }
 
+std::u16string PermissionPromptBubbleBaseView::GetAllowAlwaysText(
+    const std::vector<permissions::PermissionRequest*>& visible_requests) {
+  CHECK_GT(visible_requests.size(), 0u);
+
+  if (visible_requests.size() == 1 &&
+      visible_requests[0]->GetAllowAlwaysText().has_value()) {
+    // A prompt for a single request can use an "allow always" text that is
+    // customized for it.
+    return visible_requests[0]->GetAllowAlwaysText().value();
+  }
+
+  // Use the generic text.
+  return l10n_util::GetStringUTF16(IDS_PERMISSION_ALLOW_EVERY_VISIT);
+}
+
 void PermissionPromptBubbleBaseView::RecordDecision(
     permissions::PermissionAction action) {
   const std::string uma_suffix =
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.h b/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.h
index f562d38d..949df66 100644
--- a/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.h
+++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.h
@@ -82,7 +82,7 @@
   std::u16string GetPermissionFragmentForTesting() const;
 
  protected:
-  void CreatePermissionButtons();
+  void CreatePermissionButtons(const std::u16string& allow_always_text);
   void CreateExtraTextLabel(const std::u16string& extra_text);
 
   void CreateWidget();
@@ -97,6 +97,9 @@
   static bool IsOneTimePermission(
       permissions::PermissionPrompt::Delegate& delegate);
 
+  static std::u16string GetAllowAlwaysText(
+      const std::vector<permissions::PermissionRequest*>& visible_requests);
+
  private:
   void SetPromptStyle(PermissionPromptStyle prompt_style);
 
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble_one_origin_view.cc b/chrome/browser/ui/views/permissions/permission_prompt_bubble_one_origin_view.cc
index c84a271..218cfcf1 100644
--- a/chrome/browser/ui/views/permissions/permission_prompt_bubble_one_origin_view.cc
+++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble_one_origin_view.cc
@@ -172,7 +172,7 @@
     CreateExtraTextLabel(extra_text.value());
   }
 
-  CreatePermissionButtons();
+  CreatePermissionButtons(GetAllowAlwaysText(visible_requests));
 
   bool has_camera_request = false;
   bool has_mic_request = false;
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble_two_origins_view.cc b/chrome/browser/ui/views/permissions/permission_prompt_bubble_two_origins_view.cc
index a53eeb9..c9bc577 100644
--- a/chrome/browser/ui/views/permissions/permission_prompt_bubble_two_origins_view.cc
+++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble_two_origins_view.cc
@@ -67,7 +67,7 @@
     CreateExtraTextLabel(extra_text.value());
   }
 
-  CreatePermissionButtons();
+  CreatePermissionButtons(GetAllowAlwaysText(delegate->Requests()));
 
   // Only requests for Storage Access should use this prompt.
   CHECK(delegate);
diff --git a/chrome/browser/ui/views/side_panel/side_panel_coordinator.cc b/chrome/browser/ui/views/side_panel/side_panel_coordinator.cc
index 0789121..39f4385f 100644
--- a/chrome/browser/ui/views/side_panel/side_panel_coordinator.cc
+++ b/chrome/browser/ui/views/side_panel/side_panel_coordinator.cc
@@ -392,11 +392,10 @@
       closing_global = true;
     }
     current_entry_.reset();
-    current_entry->OnEntryHidden();
-
     if (browser_view_->toolbar()->pinned_toolbar_actions_container()) {
       NotifyPinnedContainerOfActiveStateChange(current_entry->key(), false);
     }
+    current_entry->OnEntryHidden();
   }
 
   // Reset active entry values for all observed registries and clear cache for
diff --git a/chrome/browser/ui/views/user_education/browser_user_education_service.cc b/chrome/browser/ui/views/user_education/browser_user_education_service.cc
index 7d64486..8e12b4c 100644
--- a/chrome/browser/ui/views/user_education/browser_user_education_service.cc
+++ b/chrome/browser/ui/views/user_education/browser_user_education_service.cc
@@ -658,7 +658,7 @@
           .SetBubbleTitleText(IDS_BATTERY_SAVER_MODE_PROMO_TITLE)
           .SetBubbleArrow(HelpBubbleArrow::kTopRight)));
 
-  // kIPHHighEfficiencyModeFeature:
+  // kIPHMemorySaverModeFeature:
   registry.RegisterFeature(std::move(
       FeaturePromoSpecification::CreateForCustomAction(
           feature_engagement::kIPHMemorySaverModeFeature,
diff --git a/chrome/browser/ui/views/web_apps/web_app_link_capturing_test_utils.cc b/chrome/browser/ui/views/web_apps/web_app_link_capturing_test_utils.cc
index 9f73c1cc..e4eee76 100644
--- a/chrome/browser/ui/views/web_apps/web_app_link_capturing_test_utils.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_link_capturing_test_utils.cc
@@ -5,10 +5,112 @@
 #include "chrome/browser/ui/views/web_apps/web_app_link_capturing_test_utils.h"
 
 #include "base/check_is_test.h"
+#include "base/test/test_future.h"
+#include "base/time/time.h"
+#include "chrome/browser/apps/link_capturing/link_capturing_features.h"
+#include "chrome/browser/ui/intent_picker_tab_helper.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/frame/toolbar_button_provider.h"
+#include "chrome/browser/ui/views/intent_picker_bubble_view.h"
 #include "chrome/browser/ui/views/location_bar/intent_chip_button.h"
+#include "chrome/common/chrome_features.h"
+#include "ui/events/event.h"
+#include "ui/events/types/event_type.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/test/button_test_api.h"
+#include "ui/views/widget/any_widget_observer.h"
 
 namespace web_app {
 
+IntentChipButton* GetIntentPickerIcon(Browser* browser) {
+  CHECK(apps::features::ShouldShowLinkCapturingUX());
+  return BrowserView::GetBrowserViewForBrowser(browser)
+      ->toolbar_button_provider()
+      ->GetIntentChipButton();
+}
+
+IntentPickerBubbleView* intent_picker_bubble() {
+  return IntentPickerBubbleView::intent_picker_bubble();
+}
+
+testing::AssertionResult AwaitIntentPickerTabHelperIconUpdateComplete(
+    Browser* browser) {
+  base::test::TestFuture<void> future;
+  auto* tab_helper = IntentPickerTabHelper::FromWebContents(
+      browser->tab_strip_model()->GetActiveWebContents());
+  tab_helper->SetIconUpdateCallbackForTesting(  // IN-TEST
+      future.GetCallback(), /*include_latest_navigation=*/true);
+  if (!future.Wait()) {
+    return testing::AssertionFailure()
+           << "Intent picker app did not resolve an applicable app.";
+  }
+  return testing::AssertionSuccess();
+}
+
+testing::AssertionResult WaitForIntentPickerToShow(Browser* browser) {
+  auto result = AwaitIntentPickerTabHelperIconUpdateComplete(browser);
+  if (!result) {
+    return result;
+  }
+  IntentChipButton* intent_picker_icon = GetIntentPickerIcon(browser);
+  if (!intent_picker_icon) {
+    return testing::AssertionFailure() << "Intent picker icon does not exist.";
+  }
+
+  if (!intent_picker_icon->GetVisible()) {
+    IntentChipVisibilityObserver(intent_picker_icon).WaitForChipToBeVisible();
+    if (!intent_picker_icon->GetVisible()) {
+      return testing::AssertionFailure()
+             << "Intent picker icon never became visible.";
+    }
+  }
+
+  return testing::AssertionSuccess();
+}
+
+testing::AssertionResult ClickIntentPickerChip(Browser* browser) {
+  auto result = WaitForIntentPickerToShow(browser);
+  if (!result) {
+    return result;
+  }
+
+  views::test::ButtonTestApi test_api(GetIntentPickerIcon(browser));
+  test_api.NotifyClick(ui::MouseEvent(
+      ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), base::TimeTicks(),
+      ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
+  return testing::AssertionSuccess();
+}
+
+testing::AssertionResult ClickIntentPickerAndWaitForBubble(Browser* browser) {
+  views::NamedWidgetShownWaiter intent_picker_bubble_shown(
+      views::test::AnyWidgetTestPasskey{},
+      IntentPickerBubbleView::kViewClassName);
+  auto intent_chip_click_result = ClickIntentPickerChip(browser);
+  if (!intent_chip_click_result) {
+    return intent_chip_click_result;
+  }
+
+  if (!intent_picker_bubble_shown.WaitIfNeededAndGet()) {
+    return testing::AssertionFailure()
+           << "Intent picker bubble did not appear after click.";
+  }
+
+  EXPECT_NE(intent_picker_bubble(), nullptr) << "intent picker not initialized";
+  return testing::AssertionSuccess();
+}
+
+views::Button* GetIntentPickerButtonAtIndex(size_t index) {
+  EXPECT_NE(intent_picker_bubble(), nullptr)
+      << " intent picker bubble not initialized";
+  auto children =
+      intent_picker_bubble()
+          ->GetViewByID(IntentPickerBubbleView::ViewId::kItemContainer)
+          ->children();
+  EXPECT_LE(index, children.size());
+  return static_cast<views::Button*>(children[index]);
+}
+
 IntentChipVisibilityObserver::IntentChipVisibilityObserver(
     IntentChipButton* intent_chip) {
   CHECK_IS_TEST();
diff --git a/chrome/browser/ui/views/web_apps/web_app_link_capturing_test_utils.h b/chrome/browser/ui/views/web_apps/web_app_link_capturing_test_utils.h
index a6cf25ff..b16d9d4 100644
--- a/chrome/browser/ui/views/web_apps/web_app_link_capturing_test_utils.h
+++ b/chrome/browser/ui/views/web_apps/web_app_link_capturing_test_utils.h
@@ -7,11 +7,39 @@
 
 #include "base/run_loop.h"
 #include "base/scoped_observation.h"
+#include "chrome/browser/ui/views/intent_picker_bubble_view.h"
 #include "chrome/browser/ui/views/location_bar/intent_chip_button.h"
 #include "chrome/browser/ui/views/location_bar/omnibox_chip_button.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace views {
+class Button;
+}  // namespace views
+
+class Browser;
 
 namespace web_app {
 
+// These test functions work only with the new intent picker UX and requires the
+// following flags to be enabled: features::kDesktopPWAsLinkCapturing on
+// Windows, Mac and Linux. apps::features::kLinkCapturingUiUpdate on CrOS.
+// Without these flags set on their respective platforms, the tests will CHECK
+// fail.
+IntentChipButton* GetIntentPickerIcon(Browser* browser);
+
+IntentPickerBubbleView* intent_picker_bubble();
+
+testing::AssertionResult AwaitIntentPickerTabHelperIconUpdateComplete(
+    Browser* browser);
+
+testing::AssertionResult WaitForIntentPickerToShow(Browser* browser);
+
+testing::AssertionResult ClickIntentPickerChip(Browser* browser);
+
+testing::AssertionResult ClickIntentPickerAndWaitForBubble(Browser* browser);
+
+views::Button* GetIntentPickerButtonAtIndex(size_t index);
+
 // Testing utility to wait for the IntentChipButton to be visible. The correct
 // usage for this class is: apps::IntentChipVisibilityObserver
 // visibility_observer(intent_chip); <Do something to make the chip visible>
diff --git a/chrome/browser/ui/webui/ash/settings/DEPS b/chrome/browser/ui/webui/ash/settings/DEPS
index 61318c24..46721303 100644
--- a/chrome/browser/ui/webui/ash/settings/DEPS
+++ b/chrome/browser/ui/webui/ash/settings/DEPS
@@ -22,6 +22,7 @@
   ],
   'display_settings_provider\.cc': [
     '+ash/shell.h',
+    "+ash/display/display_prefs.h",
   ],
   'fast_pair_.*': [
     "+ash/quick_pair",
diff --git a/chrome/browser/ui/webui/ash/settings/os_settings_ui.cc b/chrome/browser/ui/webui/ash/settings/os_settings_ui.cc
index df23ad2..040c885 100644
--- a/chrome/browser/ui/webui/ash/settings/os_settings_ui.cc
+++ b/chrome/browser/ui/webui/ash/settings/os_settings_ui.cc
@@ -132,6 +132,11 @@
                                IDR_NEARBY_SHARE_INTERNAL_ICONS_M_JS);
 #endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
+  // To use lottie, the worker-src CSP needs to be updated for the web ui that
+  // is using it. Since as of now there are only a couple of webuis using
+  // lottie animations, this update has to be performed manually. As the usage
+  // increases, set this as the default so manual override is no longer
+  // required.
   html_source->OverrideContentSecurityPolicy(
       network::mojom::CSPDirectiveName::WorkerSrc,
       "worker-src blob: chrome://resources 'self';");
diff --git a/chrome/browser/ui/webui/ash/settings/pages/device/display_settings/display_settings_provider.cc b/chrome/browser/ui/webui/ash/settings/pages/device/display_settings/display_settings_provider.cc
index 027e376..a20bdef 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/device/display_settings/display_settings_provider.cc
+++ b/chrome/browser/ui/webui/ash/settings/pages/device/display_settings/display_settings_provider.cc
@@ -4,20 +4,58 @@
 
 #include "chrome/browser/ui/webui/ash/settings/pages/device/display_settings/display_settings_provider.h"
 
+#include <optional>
+
+#include "ash/display/display_prefs.h"
 #include "ash/public/cpp/tablet_mode.h"
 #include "ash/shell.h"
 #include "base/metrics/histogram_functions.h"
 #include "chrome/browser/ui/webui/ash/settings/pages/device/display_settings/display_settings_provider.mojom.h"
 #include "ui/display/manager/display_manager.h"
+#include "ui/display/manager/display_manager_observer.h"
+#include "ui/display/util/display_util.h"
 
 namespace ash::settings {
 
+namespace {
+
+// Minimum/maximum bucket value of user overriding display default settings.
+constexpr int kMinTimeInMinuteOfUserOverrideDisplaySettings = 1;
+constexpr int kMaxTimeInHourOfUserOverrideDisplaySettings = 8;
+
+// The histogram bucket count of user overriding display default settings.
+constexpr int kUserOverrideDisplaySettingsTimeDeltaBucketCount = 100;
+
+// Get UMA histogram name that records the time elapsed between users changing
+// the display settings and the display is connected.
+const std::string GetUserOverrideDefaultSettingsHistogramName(
+    mojom::DisplaySettingsType type,
+    bool is_internal_display) {
+  // Should only need to handle resolution and scaling, no other display
+  // settings.
+  CHECK(type == mojom::DisplaySettingsType::kResolution ||
+        type == mojom::DisplaySettingsType::kScaling);
+
+  std::string histogram_name("ChromeOS.Settings.Display.");
+  histogram_name.append(is_internal_display ? "Internal." : "External.");
+  histogram_name.append("UserOverrideDisplayDefaultSettingsTimeElapsed.");
+  histogram_name.append(type == mojom::DisplaySettingsType::kResolution
+                            ? "Resolution"
+                            : "Scaling");
+  return histogram_name;
+}
+
+}  // namespace
+
 DisplaySettingsProvider::DisplaySettingsProvider() {
   if (TabletMode::Get()) {
     TabletMode::Get()->AddObserver(this);
   }
   if (Shell::HasInstance() && Shell::Get()->display_manager()) {
-    Shell::Get()->display_manager()->AddObserver(this);
+    Shell::Get()->display_manager()->AddObserver(
+        static_cast<display::DisplayManagerObserver*>(this));
+    Shell::Get()->display_manager()->AddObserver(
+        static_cast<display::DisplayObserver*>(this));
   }
 }
 
@@ -26,7 +64,10 @@
     TabletMode::Get()->RemoveObserver(this);
   }
   if (Shell::HasInstance() && Shell::Get()->display_manager()) {
-    Shell::Get()->display_manager()->RemoveObserver(this);
+    Shell::Get()->display_manager()->RemoveObserver(
+        static_cast<display::DisplayManagerObserver*>(this));
+    Shell::Get()->display_manager()->RemoveObserver(
+        static_cast<display::DisplayObserver*>(this));
   }
 }
 
@@ -65,6 +106,25 @@
   }
 }
 
+void DisplaySettingsProvider::OnDisplayAdded(
+    const display::Display& new_display) {
+  // Check with prefs service to see if this display is firstly seen or was
+  // saved to prefs before.
+  if (Shell::HasInstance() && Shell::Get()->display_prefs() &&
+      !Shell::Get()->display_prefs()->IsDisplayAvailableInPref(
+          new_display.id())) {
+    // Found display that is connected for the first time. Add the connection
+    // timestamp.
+    displays_connection_timestamp_map_[DisplayId(new_display.id())] =
+        base::TimeTicks::Now();
+
+    base::UmaHistogramEnumeration(kNewDisplayConnectedHistogram,
+                                  display::IsInternalDisplayId(new_display.id())
+                                      ? DisplayType::kInternalDisplay
+                                      : DisplayType::kExternalDisplay);
+  }
+}
+
 void DisplaySettingsProvider::RecordChangingDisplaySettings(
     mojom::DisplaySettingsType type,
     mojom::DisplaySettingsValuePtr value) {
@@ -75,10 +135,35 @@
     return;
   }
 
+  // Record display settings usage metrics.
   const std::string histogram_name =
       is_internal_display.value() ? kInternalDisplaySettingsHistogramName
                                   : kExternalDisplaySettingsHistogramName;
   base::UmaHistogramEnumeration(histogram_name, type);
+
+  // Record default display settings performance metrics.
+  if (value->display_id.has_value() &&
+      (type == mojom::DisplaySettingsType::kResolution ||
+       type == mojom::DisplaySettingsType::kScaling)) {
+    const DisplayId id = DisplayId(value->display_id.value());
+    auto it = displays_connection_timestamp_map_.find(id);
+    if (it != displays_connection_timestamp_map_.end()) {
+      int time_delta = (base::TimeTicks::Now() - it->second).InMinutes();
+      const std::string override_histogram_name =
+          GetUserOverrideDefaultSettingsHistogramName(
+              type, is_internal_display.value());
+      base::UmaHistogramCustomCounts(
+          override_histogram_name, time_delta,
+          kMinTimeInMinuteOfUserOverrideDisplaySettings,
+          base::Hours(kMaxTimeInHourOfUserOverrideDisplaySettings).InMinutes(),
+          kUserOverrideDisplaySettingsTimeDeltaBucketCount);
+
+      // Once user has overridden the settings, remove it from the map to
+      // prevent further recording, in which case, the user does not override
+      // system default settings, but override previous user settings.
+      displays_connection_timestamp_map_.erase(id);
+    }
+  }
 }
 
 }  // namespace ash::settings
diff --git a/chrome/browser/ui/webui/ash/settings/pages/device/display_settings/display_settings_provider.h b/chrome/browser/ui/webui/ash/settings/pages/device/display_settings/display_settings_provider.h
index 5fad0ed78..216fc24 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/device/display_settings/display_settings_provider.h
+++ b/chrome/browser/ui/webui/ash/settings/pages/device/display_settings/display_settings_provider.h
@@ -5,19 +5,28 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_DEVICE_DISPLAY_SETTINGS_DISPLAY_SETTINGS_PROVIDER_H_
 #define CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_DEVICE_DISPLAY_SETTINGS_DISPLAY_SETTINGS_PROVIDER_H_
 
+#include <map>
+
 #include "ash/public/cpp/tablet_mode_observer.h"
+#include "base/types/id_type.h"
 #include "chrome/browser/ui/webui/ash/settings/pages/device/display_settings/display_settings_provider.mojom.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote_set.h"
+#include "ui/display/display.h"
+#include "ui/display/display_observer.h"
+#include "ui/display/manager/display_manager.h"
 #include "ui/display/manager/display_manager_observer.h"
 
 namespace ash::settings {
 
+using DisplayId = base::IdType64<display::Display>;
+
 // Provide information about system display settings. Implemented in the browser
 // process. Called by the OS settings app.
 class DisplaySettingsProvider : public mojom::DisplaySettingsProvider,
                                 public TabletModeObserver,
-                                public display::DisplayManagerObserver {
+                                public display::DisplayManagerObserver,
+                                public display::DisplayObserver {
  public:
   DisplaySettingsProvider();
   ~DisplaySettingsProvider() override;
@@ -25,10 +34,21 @@
   DisplaySettingsProvider& operator=(const DisplaySettingsProvider& other) =
       delete;
 
+  // Note that these values are persisted to histograms so existing values
+  // should remain unchanged and new values should be added to the end.
+  enum class DisplayType {
+    kExternalDisplay = 0,
+    kInternalDisplay = 1,
+    kMaxValue = kInternalDisplay,
+  };
+
   static constexpr char kInternalDisplaySettingsHistogramName[] =
       "ChromeOS.Settings.Display.Internal";
   static constexpr char kExternalDisplaySettingsHistogramName[] =
       "ChromeOS.Settings.Display.External";
+  // The UMA histogram that records new display connected metrics.
+  static constexpr char kNewDisplayConnectedHistogram[] =
+      "ChromeOS.Settings.Display.NewDisplayConnected";
 
   void BindInterface(
       mojo::PendingReceiver<mojom::DisplaySettingsProvider> receiver);
@@ -53,12 +73,21 @@
   void OnDidProcessDisplayChanges(
       const DisplayConfigurationChange& configuration_change) override;
 
+  // display::DisplayObserver:
+  void OnDisplayAdded(const display::Display& new_display) override;
+
  private:
   mojo::RemoteSet<mojom::TabletModeObserver> tablet_mode_observers_;
 
   mojo::RemoteSet<mojom::DisplayConfigurationObserver>
       display_configuration_observers_;
 
+  // A map between display id and the timestamp this display is connected. Only
+  // add those displays that are connected for the first time. Used to record
+  // the time elapsed between users changing the display default settings and
+  // the display is connected.
+  std::map<DisplayId, base::TimeTicks> displays_connection_timestamp_map_;
+
   mojo::Receiver<mojom::DisplaySettingsProvider> receiver_{this};
 };
 
diff --git a/chrome/browser/ui/webui/ash/settings/pages/device/display_settings/display_settings_provider.mojom b/chrome/browser/ui/webui/ash/settings/pages/device/display_settings/display_settings_provider.mojom
index 05214cf..381a79d 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/device/display_settings/display_settings_provider.mojom
+++ b/chrome/browser/ui/webui/ash/settings/pages/device/display_settings/display_settings_provider.mojom
@@ -13,6 +13,8 @@
   kScaling,
   kOrientation,
   kOverscan,
+  kNightLight,
+  kNightLightSchedule,
   // TODO(zhangwenyu): handle more display settings.
 };
 
@@ -22,6 +24,13 @@
   // settings like toggling mirror mode apply to both internal and external
   // displays. In that case, this property will not be provided.
   bool? is_internal_display;
+
+  // The id of the display. This is optional since we mostly don't need the
+  // display id for histogram recording purpose. Only for default display
+  // settings performance metrics, this is necessary to identify the time
+  // elapsed when users change settings, otherwise those metrics will not
+  // be recorded.
+  int64? display_id;
 };
 
 // Implemented by clients that wish to be notified when the tablet mode is
diff --git a/chrome/browser/ui/webui/ash/settings/pages/device/display_settings/display_settings_provider_unittest.cc b/chrome/browser/ui/webui/ash/settings/pages/device/display_settings/display_settings_provider_unittest.cc
index 36e331d..0c73c20d 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/device/display_settings/display_settings_provider_unittest.cc
+++ b/chrome/browser/ui/webui/ash/settings/pages/device/display_settings/display_settings_provider_unittest.cc
@@ -9,7 +9,9 @@
 #include "base/test/task_environment.h"
 #include "base/test/test_future.h"
 #include "chrome/test/base/chrome_ash_test_base.h"
+#include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/display/screen.h"
 
 namespace ash::settings {
 
@@ -86,7 +88,9 @@
 
 class DisplaySettingsProviderTest : public ChromeAshTestBase {
  public:
-  DisplaySettingsProviderTest() = default;
+  DisplaySettingsProviderTest()
+      : ChromeAshTestBase(std::make_unique<content::BrowserTaskEnvironment>(
+            content::BrowserTaskEnvironment::TimeSource::MOCK_TIME)) {}
   ~DisplaySettingsProviderTest() override = default;
 
   void SetUp() override {
@@ -99,6 +103,10 @@
     ChromeAshTestBase::TearDown();
   }
 
+  void FastForwardBy(base::TimeDelta delta) {
+    task_environment()->FastForwardBy(delta);
+  }
+
  protected:
   std::unique_ptr<DisplaySettingsProvider> provider_;
   base::HistogramTester histogram_tester_;
@@ -160,4 +168,47 @@
   }
 }
 
+// Test histogram is recorded only when a display is connected for the first
+// time.
+TEST_F(DisplaySettingsProviderTest, NewDisplayConnectedHistogram) {
+  int64_t id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
+  provider_->OnDisplayAdded(display::Display(id));
+
+  // Expect to count new display is connected.
+  histogram_tester_.ExpectBucketCount(
+      DisplaySettingsProvider::kNewDisplayConnectedHistogram,
+      DisplaySettingsProvider::DisplayType::kExternalDisplay, 1);
+
+  UpdateDisplay("300x200");
+  provider_->OnDisplayAdded(display::Display(id));
+
+  // Expect not to count new display is connected since it's already saved
+  // into prefs before.
+  histogram_tester_.ExpectBucketCount(
+      DisplaySettingsProvider::kNewDisplayConnectedHistogram,
+      DisplaySettingsProvider::DisplayType::kExternalDisplay, 1);
+}
+
+// Test histogram is recorded when user overrides system default display
+// settings.
+TEST_F(DisplaySettingsProviderTest, UserOverrideDefaultSettingsHistogram) {
+  int64_t id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
+  provider_->OnDisplayAdded(display::Display(id));
+
+  constexpr uint16_t kTimeDeltaInMinute = 15;
+  FastForwardBy(base::Minutes(kTimeDeltaInMinute));
+
+  auto value = mojom::DisplaySettingsValue::New();
+  value->is_internal_display = false;
+  value->display_id = id;
+  provider_->RecordChangingDisplaySettings(
+      mojom::DisplaySettingsType::kResolution, std::move(value));
+
+  histogram_tester_.ExpectTimeBucketCount(
+      "ChromeOS.Settings.Display.External."
+      "UserOverrideDisplayDefaultSettingsTimeElapsed.Resolution",
+      base::Minutes(kTimeDeltaInMinute) / base::Minutes(1).InMilliseconds(),
+      /*expected_count=*/1);
+}
+
 }  // namespace ash::settings
diff --git a/chrome/browser/ui/webui/ash/settings/pages/multidevice/multidevice_section.cc b/chrome/browser/ui/webui/ash/settings/pages/multidevice/multidevice_section.cc
index 01259b10..c2ed1374 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/multidevice/multidevice_section.cc
+++ b/chrome/browser/ui/webui/ash/settings/pages/multidevice/multidevice_section.cc
@@ -10,6 +10,7 @@
 #include "base/no_destructor.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/branding_buildflags.h"
+#include "chrome/browser/ash/crosapi/browser_util.h"
 #include "chrome/browser/nearby_sharing/common/nearby_share_features.h"
 #include "chrome/browser/nearby_sharing/common/nearby_share_prefs.h"
 #include "chrome/browser/nearby_sharing/common/nearby_share_resource_getter.h"
@@ -324,6 +325,86 @@
          host_status == HostStatus::kHostVerified;
 }
 
+void AddNearbyShareStrings(content::WebUIDataSource* html_source) {
+  static constexpr webui::LocalizedString kLocalizedStrings[] = {
+      {"nearbyShareSetUpButtonTitle",
+       IDS_SETTINGS_NEARBY_SHARE_SET_UP_BUTTON_TITLE},
+      {"nearbyShareDeviceNameRowTitle",
+       IDS_SETTINGS_NEARBY_SHARE_DEVICE_NAME_ROW_TITLE},
+      {"nearbyShareDeviceNameDialogTitle",
+       IDS_SETTINGS_NEARBY_SHARE_DEVICE_NAME_DIALOG_TITLE},
+      {"nearbyShareDeviceNameFieldLabel",
+       IDS_SETTINGS_NEARBY_SHARE_DEVICE_NAME_FIELD_LABEL},
+      {"nearbyShareEditDeviceName", IDS_SETTINGS_NEARBY_SHARE_EDIT_DEVICE_NAME},
+      {"fastInitiationNotificationToggleTitle",
+       IDS_SETTINGS_NEARBY_SHARE_FAST_INITIATION_NOTIFICATION_TOGGLE_TITLE},
+      {"fastInitiationNotificationToggleDescription",
+       IDS_SETTINGS_NEARBY_SHARE_FAST_INITIATION_NOTIFICATION_TOGGLE_DESCRIPTION},
+      {"fastInitiationNotificationToggleAriaLabel",
+       IDS_SETTINGS_NEARBY_SHARE_FAST_INITIATION_NOTIFICATION_TOGGLE_ARIA_LABEL},
+      {"nearbyShareDeviceNameAriaDescription",
+       IDS_SETTINGS_NEARBY_SHARE_DEVICE_NAME_ARIA_DESCRIPTION},
+      {"nearbyShareConfirmDeviceName",
+       IDS_SETTINGS_NEARBY_SHARE_CONFIRM_DEVICE_NAME},
+      {"nearbyShareManageContactsLabel",
+       IDS_SETTINGS_NEARBY_SHARE_MANAGE_CONTACTS_LABEL},
+      {"nearbyShareManageContactsRowTitle",
+       IDS_SETTINGS_NEARBY_SHARE_MANAGE_CONTACTS_ROW_TITLE},
+      {"nearbyShareEditDataUsage", IDS_SETTINGS_NEARBY_SHARE_EDIT_DATA_USAGE},
+      {"nearbyShareUpdateDataUsage",
+       IDS_SETTINGS_NEARBY_SHARE_UPDATE_DATA_USAGE},
+      {"nearbyShareDataUsageDialogTitle",
+       IDS_SETTINGS_NEARBY_SHARE_DATA_USAGE_DIALOG_TITLE},
+      {"nearbyShareDataUsageWifiOnlyLabel",
+       IDS_SETTINGS_NEARBY_SHARE_DATA_USAGE_WIFI_ONLY_LABEL},
+      {"nearbyShareDataUsageWifiOnlyDescription",
+       IDS_SETTINGS_NEARBY_SHARE_DATA_USAGE_WIFI_ONLY_DESCRIPTION},
+      {"nearbyShareDataUsageDataLabel",
+       IDS_SETTINGS_NEARBY_SHARE_DATA_USAGE_MOBILE_DATA_LABEL},
+      {"nearbyShareDataUsageDataDescription",
+       IDS_SETTINGS_NEARBY_SHARE_DATA_USAGE_MOBILE_DATA_DESCRIPTION},
+      {"nearbyShareDataUsageDataTooltip",
+       IDS_SETTINGS_NEARBY_SHARE_DATA_USAGE_MOBILE_DATA_TOOLTIP},
+      {"nearbyShareDataUsageOfflineLabel",
+       IDS_SETTINGS_NEARBY_SHARE_DATA_USAGE_OFFLINE_LABEL},
+      {"nearbyShareDataUsageOfflineDescription",
+       IDS_SETTINGS_NEARBY_SHARE_DATA_USAGE_OFFLINE_DESCRIPTION},
+      {"nearbyShareDataUsageDataEditButtonDescription",
+       IDS_SETTINGS_NEARBY_SHARE_DATA_USAGE_EDIT_BUTTON_DATA_DESCRIPTION},
+      {"nearbyShareDataUsageWifiOnlyEditButtonDescription",
+       IDS_SETTINGS_NEARBY_SHARE_DATA_USAGE_EDIT_BUTTON_WIFI_ONLY_DESCRIPTION},
+      {"nearbyShareDataUsageOfflineEditButtonDescription",
+       IDS_SETTINGS_NEARBY_SHARE_DATA_USAGE_EDIT_BUTTON_OFFLINE_DESCRIPTION},
+      {"nearbyShareContactVisibilityRowTitle",
+       IDS_SETTINGS_NEARBY_SHARE_CONTACT_VISIBILITY_ROW_TITLE},
+      {"nearbyShareEditVisibility", IDS_SETTINGS_NEARBY_SHARE_EDIT_VISIBILITY},
+      {"nearbyShareVisibilityDialogTitle",
+       IDS_SETTINGS_NEARBY_SHARE_VISIBILITY_DIALOG_TITLE},
+      {"nearbyShareDescription", IDS_SETTINGS_NEARBY_SHARE_DESCRIPTION},
+      {"nearbyShareHighVisibilityTitle",
+       IDS_SETTINGS_NEARBY_SHARE_HIGH_VISIBILITY_TITLE},
+      {"nearbyShareHighVisibilityOn",
+       IDS_SETTINGS_NEARBY_SHARE_HIGH_VISIBILITY_ON},
+      {"nearbyShareHighVisibilityOff",
+       IDS_SETTINGS_NEARBY_SHARE_HIGH_VISIBILITY_OFF},
+      {"nearbyShareVisibilityDialogSave",
+       IDS_SETTINGS_NEARBY_SHARE_VISIBILITY_DIALOG_SAVE}};
+
+  html_source->AddLocalizedStrings(kLocalizedStrings);
+
+  const char localized_title_string[] = "nearbyShareTitle";
+
+  if (::features::IsNameEnabled()) {
+    html_source->AddString(
+        localized_title_string,
+        NearbyShareResourceGetter::GetInstance()->GetStringWithFeatureName(
+            IDS_SETTINGS_NEARBY_SHARE_TITLE_PH));
+  } else {
+    html_source->AddLocalizedString(localized_title_string,
+                                    IDS_SETTINGS_NEARBY_SHARE_TITLE);
+  }
+}
+
 }  // namespace
 
 MultiDeviceSection::MultiDeviceSection(
@@ -671,7 +752,7 @@
   // We still need to register strings even if Nearby Share is not supported.
   // For example, the HTML is always built but only displayed if Nearby Share is
   // supported.
-  ::settings::AddNearbyShareData(html_source);
+  AddNearbyShareStrings(html_source);
   RegisterNearbySharedStrings(html_source);
   html_source->AddBoolean(
       "isNearbyShareSupported",
diff --git a/chrome/browser/ui/webui/favicon_source.cc b/chrome/browser/ui/webui/favicon_source.cc
index 829ca7c..0206534c 100644
--- a/chrome/browser/ui/webui/favicon_source.cc
+++ b/chrome/browser/ui/webui/favicon_source.cc
@@ -122,18 +122,6 @@
     return;
   }
 
-  if (url_format_ == chrome::FaviconUrlFormat::kFaviconLegacy) {
-    const extensions::Extension* extension =
-        extensions::ExtensionRegistry::Get(profile_)
-            ->enabled_extensions()
-            .GetExtensionOrAppByURL(GetUnsafeRequestOrigin(wc_getter));
-    if (extension) {
-      base::UmaHistogramEnumeration("Extensions.FaviconResourceRequested",
-                                    extension->GetType(),
-                                    extensions::Manifest::NUM_LOAD_TYPES);
-    }
-  }
-
   if (parsed.page_url.empty()) {
     // Request by icon url.
 
diff --git a/chrome/browser/ui/webui/favicon_source_unittest.cc b/chrome/browser/ui/webui/favicon_source_unittest.cc
index eea0bebe..2563c44 100644
--- a/chrome/browser/ui/webui/favicon_source_unittest.cc
+++ b/chrome/browser/ui/webui/favicon_source_unittest.cc
@@ -200,16 +200,6 @@
       test_web_contents_getter_, base::DoNothing());
 }
 
-TEST_F(FaviconSourceTestWithLegacyFormat,
-       ShouldRecordFaviconResourceHistogram_NonExtensionOrigin) {
-  base::HistogramTester tester;
-  source()->StartDataRequest(
-      GURL(base::StrCat({kDummyPrefix, "size/16@1x/https://www.google.com"})),
-      test_web_contents_getter_, base::DoNothing());
-  tester.ExpectBucketCount("Extensions.FaviconResourceRequested",
-                           extensions::Manifest::TYPE_EXTENSION, 0);
-}
-
 TEST_F(FaviconSourceTestWithLegacyFormat, ShouldNotQueryIfDesiredSizeTooLarge) {
   EXPECT_CALL(*mock_history_ui_favicon_request_handler_,
               GetRawFaviconForPageURL)
@@ -237,21 +227,6 @@
       test_web_contents_getter_, base::DoNothing());
 }
 
-TEST_F(FaviconSourceTestWithLegacyFormat,
-       ShouldRecordFaviconResourceHistogram_ExtensionOrigin) {
-  scoped_refptr<const extensions::Extension> extension =
-      extensions::ExtensionBuilder("one").Build();
-  extensions::ExtensionRegistry::Get(&profile_)->AddEnabled(extension);
-  content::WebContentsTester::For(test_web_contents_.get())
-      ->SetLastCommittedURL(extension->url());
-  base::HistogramTester tester;
-  source()->StartDataRequest(
-      GURL(base::StrCat({kDummyPrefix, "size/16@1x/https://www.google.com"})),
-      test_web_contents_getter_, base::DoNothing());
-  tester.ExpectBucketCount("Extensions.FaviconResourceRequested",
-                           extensions::Manifest::TYPE_EXTENSION, 1);
-}
-
 TEST_F(FaviconSourceTestWithFavicon2Format,
        ShouldNotRecordFaviconResourceHistogram) {
   base::HistogramTester tester;
diff --git a/chrome/browser/ui/webui/nearby_internals/DEPS b/chrome/browser/ui/webui/nearby_internals/DEPS
index 6784467..a5ac2b9 100644
--- a/chrome/browser/ui/webui/nearby_internals/DEPS
+++ b/chrome/browser/ui/webui/nearby_internals/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
   "+components/cross_device/logging",
   "+third_party/nearby",
+  "+components/push_notification",
 ]
diff --git a/chrome/browser/ui/webui/nearby_internals/nearby_internals_chime_handler.cc b/chrome/browser/ui/webui/nearby_internals/nearby_internals_chime_handler.cc
deleted file mode 100644
index 6a8c0bb..0000000
--- a/chrome/browser/ui/webui/nearby_internals/nearby_internals_chime_handler.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/webui/nearby_internals/nearby_internals_chime_handler.h"
-
-NearbyInternalsChimeHandler::NearbyInternalsChimeHandler() = default;
-
-NearbyInternalsChimeHandler::~NearbyInternalsChimeHandler() = default;
-
-void NearbyInternalsChimeHandler::RegisterMessages() {
-  web_ui()->RegisterMessageCallback(
-      "AddChimeClient",
-      base::BindRepeating(&NearbyInternalsChimeHandler::HandleAddChimeClient,
-                          base::Unretained(this)));
-  web_ui()->RegisterMessageCallback(
-      "InitializeChimeHandler",
-      base::BindRepeating(&NearbyInternalsChimeHandler::Initialize,
-                          base::Unretained(this)));
-}
-
-void NearbyInternalsChimeHandler::OnJavascriptAllowed() {}
-
-void NearbyInternalsChimeHandler::OnJavascriptDisallowed() {}
-
-void NearbyInternalsChimeHandler::Initialize(const base::Value::List& args) {
-  AllowJavascript();
-}
-
-// TODO(b/306399642): Once the Chime `KeyedService` and `ChimeClient` base class
-// is created, this function will be used to retrieve the service and then add
-// `NearbyInternalsChimeHandler` as a `ChimeClient` to `ChimeClientManager`.
-void NearbyInternalsChimeHandler::HandleAddChimeClient(
-    const base::Value::List& args) {}
diff --git a/chrome/browser/ui/webui/nearby_internals/nearby_internals_chime_handler.h b/chrome/browser/ui/webui/nearby_internals/nearby_internals_chime_handler.h
deleted file mode 100644
index faf4ec0..0000000
--- a/chrome/browser/ui/webui/nearby_internals/nearby_internals_chime_handler.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_WEBUI_NEARBY_INTERNALS_NEARBY_INTERNALS_CHIME_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_NEARBY_INTERNALS_NEARBY_INTERNALS_CHIME_HANDLER_H_
-
-#include "base/memory/weak_ptr.h"
-#include "base/values.h"
-#include "content/public/browser/web_ui_message_handler.h"
-
-class NearbyInternalsChimeHandler : public content::WebUIMessageHandler {
- public:
-  NearbyInternalsChimeHandler();
-  NearbyInternalsChimeHandler(const NearbyInternalsChimeHandler&) = delete;
-  NearbyInternalsChimeHandler& operator=(const NearbyInternalsChimeHandler&) =
-      delete;
-  ~NearbyInternalsChimeHandler() override;
-
-  // content::WebUIMessageHandler:
-  void RegisterMessages() override;
-  void OnJavascriptAllowed() override;
-  void OnJavascriptDisallowed() override;
-
- private:
-  void Initialize(const base::Value::List& args);
-  void HandleAddChimeClient(const base::Value::List& args);
-
-  base::WeakPtrFactory<NearbyInternalsChimeHandler> weak_ptr_factory_{this};
-};
-
-#endif  // CHROME_BROWSER_UI_WEBUI_NEARBY_INTERNALS_NEARBY_INTERNALS_CHIME_HANDLER_H_
diff --git a/chrome/browser/ui/webui/nearby_internals/nearby_internals_push_notification_handler.cc b/chrome/browser/ui/webui/nearby_internals/nearby_internals_push_notification_handler.cc
new file mode 100644
index 0000000..e282324
--- /dev/null
+++ b/chrome/browser/ui/webui/nearby_internals/nearby_internals_push_notification_handler.cc
@@ -0,0 +1,47 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/nearby_internals/nearby_internals_push_notification_handler.h"
+#include "chrome/browser/push_notification/push_notification_service_factory.h"
+#include "components/push_notification/push_notification_service.h"
+
+NearbyInternalsPushNotificationHandler::NearbyInternalsPushNotificationHandler(
+    content::BrowserContext* context)
+    : context_(context) {}
+
+NearbyInternalsPushNotificationHandler::
+    ~NearbyInternalsPushNotificationHandler() = default;
+
+void NearbyInternalsPushNotificationHandler::RegisterMessages() {
+  web_ui()->RegisterMessageCallback(
+      "AddPushNotificationClient",
+      base::BindRepeating(&NearbyInternalsPushNotificationHandler::
+                              HandleAddPushNotificationClient,
+                          base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "InitializePushNotificationHandler",
+      base::BindRepeating(&NearbyInternalsPushNotificationHandler::Initialize,
+                          base::Unretained(this)));
+}
+
+void NearbyInternalsPushNotificationHandler::OnJavascriptAllowed() {}
+
+void NearbyInternalsPushNotificationHandler::OnJavascriptDisallowed() {}
+
+void NearbyInternalsPushNotificationHandler::Initialize(
+    const base::Value::List& args) {
+  AllowJavascript();
+}
+
+// TODO(b/306399642): Once the `PushNotificationClient` base class is created,
+// this function will be used to retrieve the service and then add
+// `NearbyInternalsPushNotificationHandler` as a `PushNotificationClient` to
+// `PushNotificationClientManager`.
+void NearbyInternalsPushNotificationHandler::HandleAddPushNotificationClient(
+    const base::Value::List& args) {
+  push_notification::PushNotificationService* service =
+      push_notification::PushNotificationServiceFactory::GetForBrowserContext(
+          context_);
+  CHECK(service);
+}
diff --git a/chrome/browser/ui/webui/nearby_internals/nearby_internals_push_notification_handler.h b/chrome/browser/ui/webui/nearby_internals/nearby_internals_push_notification_handler.h
new file mode 100644
index 0000000..deb562f
--- /dev/null
+++ b/chrome/browser/ui/webui/nearby_internals/nearby_internals_push_notification_handler.h
@@ -0,0 +1,41 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_NEARBY_INTERNALS_NEARBY_INTERNALS_PUSH_NOTIFICATION_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_NEARBY_INTERNALS_NEARBY_INTERNALS_PUSH_NOTIFICATION_HANDLER_H_
+
+#include "base/memory/weak_ptr.h"
+#include "base/values.h"
+#include "content/public/browser/web_ui_message_handler.h"
+
+namespace content {
+class BrowserContext;
+}  // namespace content
+
+class NearbyInternalsPushNotificationHandler
+    : public content::WebUIMessageHandler {
+ public:
+  explicit NearbyInternalsPushNotificationHandler(
+      content::BrowserContext* context);
+  NearbyInternalsPushNotificationHandler(
+      const NearbyInternalsPushNotificationHandler&) = delete;
+  NearbyInternalsPushNotificationHandler& operator=(
+      const NearbyInternalsPushNotificationHandler&) = delete;
+  ~NearbyInternalsPushNotificationHandler() override;
+
+  // content::WebUIMessageHandler:
+  void RegisterMessages() override;
+  void OnJavascriptAllowed() override;
+  void OnJavascriptDisallowed() override;
+
+ private:
+  void Initialize(const base::Value::List& args);
+  void HandleAddPushNotificationClient(const base::Value::List& args);
+
+  const raw_ptr<content::BrowserContext> context_;
+  base::WeakPtrFactory<NearbyInternalsPushNotificationHandler>
+      weak_ptr_factory_{this};
+};
+
+#endif  // CHROME_BROWSER_UI_WEBUI_NEARBY_INTERNALS_NEARBY_INTERNALS_PUSH_NOTIFICATION_HANDLER_H_
diff --git a/chrome/browser/ui/webui/nearby_internals/nearby_internals_ui.cc b/chrome/browser/ui/webui/nearby_internals/nearby_internals_ui.cc
index 40449d9..c212108d 100644
--- a/chrome/browser/ui/webui/nearby_internals/nearby_internals_ui.cc
+++ b/chrome/browser/ui/webui/nearby_internals/nearby_internals_ui.cc
@@ -10,11 +10,11 @@
 #include "base/feature_list.h"
 #include "chrome/browser/nearby_sharing/common/nearby_share_features.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/webui/nearby_internals/nearby_internals_chime_handler.h"
 #include "chrome/browser/ui/webui/nearby_internals/nearby_internals_contact_handler.h"
 #include "chrome/browser/ui/webui/nearby_internals/nearby_internals_http_handler.h"
 #include "chrome/browser/ui/webui/nearby_internals/nearby_internals_logs_handler.h"
 #include "chrome/browser/ui/webui/nearby_internals/nearby_internals_prefs_handler.h"
+#include "chrome/browser/ui/webui/nearby_internals/nearby_internals_push_notification_handler.h"
 #include "chrome/browser/ui/webui/nearby_internals/nearby_internals_ui_presence_handler.h"
 #include "chrome/browser/ui/webui/nearby_internals/nearby_internals_ui_trigger_handler.h"
 #include "chrome/browser/ui/webui/nearby_internals/quick_pair/quick_pair_handler.h"
@@ -51,7 +51,8 @@
       std::make_unique<NearbyInternalsPrefsHandler>(context));
   web_ui->AddMessageHandler(
       std::make_unique<NearbyInternalsPresenceHandler>(context));
-  web_ui->AddMessageHandler(std::make_unique<NearbyInternalsChimeHandler>());
+  web_ui->AddMessageHandler(
+      std::make_unique<NearbyInternalsPushNotificationHandler>(context));
   web_ui->AddMessageHandler(
       std::make_unique<NearbyInternalsUiTriggerHandler>(context));
   web_ui->AddMessageHandler(std::make_unique<QuickPairHandler>());
diff --git a/chrome/browser/ui/webui/privacy_sandbox/BUILD.gn b/chrome/browser/ui/webui/privacy_sandbox/BUILD.gn
new file mode 100644
index 0000000..06e0f10
--- /dev/null
+++ b/chrome/browser/ui/webui/privacy_sandbox/BUILD.gn
@@ -0,0 +1,12 @@
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("mojo_bindings") {
+  disable_variants = true
+  public_deps = [
+    "//components/content_settings/core/common:mojo_bindings",
+    "//mojo/public/mojom/base",
+  ]
+
+  sources = [ "privacy_sandbox_internals.mojom" ]
+  webui_module_path = "/"
+}
diff --git a/chrome/browser/ui/webui/privacy_sandbox/OWNERS b/chrome/browser/ui/webui/privacy_sandbox/OWNERS
index 230e9a1d..e3ef87c7 100644
--- a/chrome/browser/ui/webui/privacy_sandbox/OWNERS
+++ b/chrome/browser/ui/webui/privacy_sandbox/OWNERS
@@ -1 +1,4 @@
 file://components/privacy_sandbox/OWNERS
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals.mojom b/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals.mojom
new file mode 100644
index 0000000..52327ac
--- /dev/null
+++ b/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals.mojom
@@ -0,0 +1,25 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+module privacy_sandbox_internals.mojom;
+
+import "mojo/public/mojom/base/values.mojom";
+import "components/content_settings/core/common/content_settings.mojom";
+
+// Mojo interface for DevUI access to data for Privacy Sandbox state.
+
+// Renderer -> Browser
+interface PageHandler {
+  // Return a list of ContentSettings for the current profile.
+  GetCookieContentSettings() => (
+    array<content_settings.mojom.ContentSettingPatternSource> content_settings);
+
+  // Convert PatternParts into a string representation.
+  ContentSettingsPatternToString(
+    content_settings.mojom.ContentSettingsPattern pattern) => (string s);
+};
+
+
+// Browser -> Renderer
+interface Page {
+};
diff --git a/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals_handler.cc b/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals_handler.cc
new file mode 100644
index 0000000..82881d43a
--- /dev/null
+++ b/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals_handler.cc
@@ -0,0 +1,30 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include "chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals_handler.h"
+#include "base/logging.h"
+#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/content_settings/core/common/content_settings_pattern_parser.h"
+#include "privacy_sandbox_internals_handler.h"
+
+PrivacySandboxInternalsHandler::PrivacySandboxInternalsHandler(Profile* profile)
+    : profile_(profile) {}
+
+PrivacySandboxInternalsHandler::~PrivacySandboxInternalsHandler() = default;
+
+void PrivacySandboxInternalsHandler::GetCookieContentSettings(
+    GetCookieContentSettingsCallback callback) {
+  HostContentSettingsMap* map =
+      HostContentSettingsMapFactory::GetForProfile(profile_);
+  std::vector<ContentSettingPatternSource> content_settings =
+      map->GetSettingsForOneType(ContentSettingsType::COOKIES);
+
+  std::move(callback).Run(std::move(content_settings));
+}
+
+void PrivacySandboxInternalsHandler::ContentSettingsPatternToString(
+    const ContentSettingsPattern& pattern,
+    ContentSettingsPatternToStringCallback callback) {
+  std::move(callback).Run(pattern.ToString());
+}
diff --git a/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals_handler.h b/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals_handler.h
new file mode 100644
index 0000000..0703b3e5
--- /dev/null
+++ b/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals_handler.h
@@ -0,0 +1,35 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#ifndef CHROME_BROWSER_UI_WEBUI_PRIVACY_SANDBOX_PRIVACY_SANDBOX_INTERNALS_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_PRIVACY_SANDBOX_PRIVACY_SANDBOX_INTERNALS_HANDLER_H_
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals.mojom.h"
+#include "components/content_settings/core/common/content_settings_pattern.h"
+
+class PrivacySandboxInternalsHandler
+    : public privacy_sandbox_internals::mojom::PageHandler {
+ public:
+  explicit PrivacySandboxInternalsHandler(Profile* profile);
+
+  ~PrivacySandboxInternalsHandler() override;
+
+  // Movable, not copyable.
+  PrivacySandboxInternalsHandler(PrivacySandboxInternalsHandler&&) = default;
+  PrivacySandboxInternalsHandler(const PrivacySandboxInternalsHandler&) =
+      delete;
+  PrivacySandboxInternalsHandler& operator=(
+      const PrivacySandboxInternalsHandler&) = delete;
+
+  void GetCookieContentSettings(
+      GetCookieContentSettingsCallback callback) override;
+  void ContentSettingsPatternToString(
+      const ContentSettingsPattern& pattern,
+      ContentSettingsPatternToStringCallback callback) override;
+
+ private:
+  raw_ptr<Profile> profile_;
+};
+
+#endif  // CHROME_BROWSER_UI_WEBUI_PRIVACY_SANDBOX_PRIVACY_SANDBOX_INTERNALS_HANDLER_H_
diff --git a/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals_handler_browsertest.cc b/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals_handler_browsertest.cc
new file mode 100644
index 0000000..1d21d62
--- /dev/null
+++ b/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals_handler_browsertest.cc
@@ -0,0 +1,151 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include "base/functional/bind.h"
+#include "base/run_loop.h"
+#include "base/test/bind.h"
+#include "chrome/browser/content_settings/cookie_settings_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals.mojom.h"
+#include "chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals_handler.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "components/content_settings/core/browser/cookie_settings.h"
+#include "components/content_settings/core/common/content_settings.h"
+#include "components/content_settings/core/common/content_settings_pattern_parser.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/test_utils.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+using ::privacy_sandbox_internals::mojom::PageHandler;
+using ::testing::AllOf;
+using ::testing::Ge;
+using ::testing::SizeIs;
+using ::testing::StrEq;
+using ::testing::UnorderedElementsAreArray;
+
+// Helper to aid in waiting for mojo callbacks to happen.
+class CallbackWaiter {
+ public:
+  void Notify() {
+    waiting_ = false;
+    if (runner_.get()) {
+      runner_->Quit();
+    }
+  }
+
+  void Wait() {
+    if (waiting_) {
+      runner_ = std::make_unique<base::RunLoop>();
+      runner_->Run();
+      runner_.reset();
+    }
+  }
+
+  void Reset() {
+    waiting_ = true;
+    if (runner_.get()) {
+      runner_->Quit();
+    }
+    runner_.reset();
+  }
+
+ private:
+  bool waiting_{true};
+  std::unique_ptr<base::RunLoop> runner_;
+};
+
+// Given an implementation `Handler` of a mojo handler for `Interface`, will
+// wire up a pipe with this object acting as the remote (client) side.
+template <typename Handler, typename Interface>
+class MojoPiping {
+ public:
+  explicit MojoPiping(Handler handler)
+      : handler_(std::move(handler)),
+        // Connect both ends to the mojo pipe.  The `Remote` is the client end
+        // and the `Receiver` is the end connected to the handler.
+        remote_(mojo::PendingRemote<Interface>(std::move(pipe_.handle0), 0)),
+        receiver_(&handler_,
+                  mojo::PendingReceiver<Interface>(std::move(pipe_.handle1))) {}
+
+  // For this test we only care about access to the `Remote` object since the
+  // test is acting as a client.
+  typename Interface::Proxy_* get() const { return remote_.get(); }
+  typename Interface::Proxy_* operator->() const { return get(); }
+  typename Interface::Proxy_& operator*() const { return *get(); }
+
+ private:
+  mojo::MessagePipe pipe_;
+  Handler handler_;
+  mojo::Remote<PageHandler> remote_;
+  mojo::Receiver<PageHandler> receiver_;
+};
+
+class PrivacySandboxInternalsMojoTest : public InProcessBrowserTest {
+ public:
+  PrivacySandboxInternalsMojoTest() = default;
+
+  MojoPiping<PrivacySandboxInternalsHandler, PageHandler> MakeMojoPiping() {
+    return MojoPiping<PrivacySandboxInternalsHandler, PageHandler>(
+        PrivacySandboxInternalsHandler(browser()->profile()));
+  }
+
+  void GetCookieContentSettingsCallback(
+      const std::vector<ContentSettingPatternSource>& vec) {
+    get_cookie_content_settings_cb_data_ = vec;
+    waiter_.Notify();
+  }
+
+  void ContentSettingsPatternToStringCallback(const std::string& s) {
+    content_settings_pattern_to_string_cb_data_ = s;
+    waiter_.Notify();
+  }
+
+ protected:
+  // Notified when _any_ callback from the mojo interface is made.
+  CallbackWaiter waiter_;
+
+  std::vector<ContentSettingPatternSource> get_cookie_content_settings_cb_data_;
+  std::string content_settings_pattern_to_string_cb_data_;
+};
+
+IN_PROC_BROWSER_TEST_F(PrivacySandboxInternalsMojoTest,
+                       GetCookieContentSettings) {
+  auto mojo = MakeMojoPiping();
+  content_settings::CookieSettings* settings =
+      CookieSettingsFactory::GetForProfile(browser()->profile()).get();
+  settings->SetCookieSetting(GURL("https://example.com"),
+                             CONTENT_SETTING_ALLOW);
+
+  mojo->GetCookieContentSettings(base::BindOnce(
+      &PrivacySandboxInternalsMojoTest::GetCookieContentSettingsCallback,
+      base::Unretained(this)));
+  waiter_.Wait();
+  EXPECT_THAT(
+      get_cookie_content_settings_cb_data_,
+      AllOf(
+          UnorderedElementsAreArray(settings->GetCookieSettings()),
+          SizeIs(Ge(1u))));  // Don't check exact size (default list may change)
+}
+
+IN_PROC_BROWSER_TEST_F(PrivacySandboxInternalsMojoTest, PatternPartsToString) {
+  auto mojo = MakeMojoPiping();
+
+  for (const std::string& regex :
+       {"[*.]example.com", "http://example.net", "example.org"}) {
+    ContentSettingsPattern pattern = ContentSettingsPattern::FromString(regex);
+    mojo->ContentSettingsPatternToString(
+        pattern, base::BindOnce(&PrivacySandboxInternalsMojoTest::
+                                    ContentSettingsPatternToStringCallback,
+                                base::Unretained(this)));
+    waiter_.Wait();
+    waiter_.Reset();
+    EXPECT_THAT(content_settings_pattern_to_string_cb_data_,
+                StrEq(pattern.ToString()));
+  }
+}
+}  // namespace
diff --git a/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc
index f32cab4..c3072e9b 100644
--- a/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc
@@ -31,15 +31,11 @@
 #include "content/public/browser/web_ui_data_source.h"
 #include "content/public/common/content_features.h"
 #include "media/base/media_switches.h"
-#include "services/network/public/mojom/content_security_policy.mojom.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/webui/web_ui_util.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/constants/ash_features.h"
-#include "chrome/browser/ash/crosapi/browser_util.h"
-#include "chrome/browser/nearby_sharing/common/nearby_share_features.h"
-#include "chrome/browser/nearby_sharing/common/nearby_share_resource_getter.h"
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if BUILDFLAG(IS_CHROMEOS)
@@ -259,98 +255,6 @@
   html_source->AddString("syncErrorsHelpUrl", chrome::kSyncErrorsHelpURL);
 }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-// TODO(b/309864078): move `AddNearbyShareData` to multidevice section.
-void AddNearbyShareData(content::WebUIDataSource* html_source) {
-  static constexpr webui::LocalizedString kLocalizedStrings[] = {
-      {"nearbyShareSetUpButtonTitle",
-       IDS_SETTINGS_NEARBY_SHARE_SET_UP_BUTTON_TITLE},
-      {"nearbyShareDeviceNameRowTitle",
-       IDS_SETTINGS_NEARBY_SHARE_DEVICE_NAME_ROW_TITLE},
-      {"nearbyShareDeviceNameDialogTitle",
-       IDS_SETTINGS_NEARBY_SHARE_DEVICE_NAME_DIALOG_TITLE},
-      {"nearbyShareDeviceNameFieldLabel",
-       IDS_SETTINGS_NEARBY_SHARE_DEVICE_NAME_FIELD_LABEL},
-      {"nearbyShareEditDeviceName", IDS_SETTINGS_NEARBY_SHARE_EDIT_DEVICE_NAME},
-      {"fastInitiationNotificationToggleTitle",
-       IDS_SETTINGS_NEARBY_SHARE_FAST_INITIATION_NOTIFICATION_TOGGLE_TITLE},
-      {"fastInitiationNotificationToggleDescription",
-       IDS_SETTINGS_NEARBY_SHARE_FAST_INITIATION_NOTIFICATION_TOGGLE_DESCRIPTION},
-      {"fastInitiationNotificationToggleAriaLabel",
-       IDS_SETTINGS_NEARBY_SHARE_FAST_INITIATION_NOTIFICATION_TOGGLE_ARIA_LABEL},
-      {"nearbyShareDeviceNameAriaDescription",
-       IDS_SETTINGS_NEARBY_SHARE_DEVICE_NAME_ARIA_DESCRIPTION},
-      {"nearbyShareConfirmDeviceName",
-       IDS_SETTINGS_NEARBY_SHARE_CONFIRM_DEVICE_NAME},
-      {"nearbyShareManageContactsLabel",
-       IDS_SETTINGS_NEARBY_SHARE_MANAGE_CONTACTS_LABEL},
-      {"nearbyShareManageContactsRowTitle",
-       IDS_SETTINGS_NEARBY_SHARE_MANAGE_CONTACTS_ROW_TITLE},
-      {"nearbyShareEditDataUsage", IDS_SETTINGS_NEARBY_SHARE_EDIT_DATA_USAGE},
-      {"nearbyShareUpdateDataUsage",
-       IDS_SETTINGS_NEARBY_SHARE_UPDATE_DATA_USAGE},
-      {"nearbyShareDataUsageDialogTitle",
-       IDS_SETTINGS_NEARBY_SHARE_DATA_USAGE_DIALOG_TITLE},
-      {"nearbyShareDataUsageWifiOnlyLabel",
-       IDS_SETTINGS_NEARBY_SHARE_DATA_USAGE_WIFI_ONLY_LABEL},
-      {"nearbyShareDataUsageWifiOnlyDescription",
-       IDS_SETTINGS_NEARBY_SHARE_DATA_USAGE_WIFI_ONLY_DESCRIPTION},
-      {"nearbyShareDataUsageDataLabel",
-       IDS_SETTINGS_NEARBY_SHARE_DATA_USAGE_MOBILE_DATA_LABEL},
-      {"nearbyShareDataUsageDataDescription",
-       IDS_SETTINGS_NEARBY_SHARE_DATA_USAGE_MOBILE_DATA_DESCRIPTION},
-      {"nearbyShareDataUsageDataTooltip",
-       IDS_SETTINGS_NEARBY_SHARE_DATA_USAGE_MOBILE_DATA_TOOLTIP},
-      {"nearbyShareDataUsageOfflineLabel",
-       IDS_SETTINGS_NEARBY_SHARE_DATA_USAGE_OFFLINE_LABEL},
-      {"nearbyShareDataUsageOfflineDescription",
-       IDS_SETTINGS_NEARBY_SHARE_DATA_USAGE_OFFLINE_DESCRIPTION},
-      {"nearbyShareDataUsageDataEditButtonDescription",
-       IDS_SETTINGS_NEARBY_SHARE_DATA_USAGE_EDIT_BUTTON_DATA_DESCRIPTION},
-      {"nearbyShareDataUsageWifiOnlyEditButtonDescription",
-       IDS_SETTINGS_NEARBY_SHARE_DATA_USAGE_EDIT_BUTTON_WIFI_ONLY_DESCRIPTION},
-      {"nearbyShareDataUsageOfflineEditButtonDescription",
-       IDS_SETTINGS_NEARBY_SHARE_DATA_USAGE_EDIT_BUTTON_OFFLINE_DESCRIPTION},
-      {"nearbyShareContactVisibilityRowTitle",
-       IDS_SETTINGS_NEARBY_SHARE_CONTACT_VISIBILITY_ROW_TITLE},
-      {"nearbyShareEditVisibility", IDS_SETTINGS_NEARBY_SHARE_EDIT_VISIBILITY},
-      {"nearbyShareVisibilityDialogTitle",
-       IDS_SETTINGS_NEARBY_SHARE_VISIBILITY_DIALOG_TITLE},
-      {"nearbyShareDescription", IDS_SETTINGS_NEARBY_SHARE_DESCRIPTION},
-      {"nearbyShareHighVisibilityTitle",
-       IDS_SETTINGS_NEARBY_SHARE_HIGH_VISIBILITY_TITLE},
-      {"nearbyShareHighVisibilityOn",
-       IDS_SETTINGS_NEARBY_SHARE_HIGH_VISIBILITY_ON},
-      {"nearbyShareHighVisibilityOff",
-       IDS_SETTINGS_NEARBY_SHARE_HIGH_VISIBILITY_OFF},
-      {"nearbyShareVisibilityDialogSave",
-       IDS_SETTINGS_NEARBY_SHARE_VISIBILITY_DIALOG_SAVE}};
-
-  html_source->AddLocalizedStrings(kLocalizedStrings);
-
-  const char localized_title_string[] = "nearbyShareTitle";
-
-  if (features::IsNameEnabled()) {
-    html_source->AddString(
-        localized_title_string,
-        NearbyShareResourceGetter::GetInstance()->GetStringWithFeatureName(
-            IDS_SETTINGS_NEARBY_SHARE_TITLE_PH));
-  } else {
-    html_source->AddLocalizedString(localized_title_string,
-                                    IDS_SETTINGS_NEARBY_SHARE_TITLE);
-  }
-
-  // To use lottie, the worker-src CSP needs to be updated for the web ui that
-  // is using it. Since as of now there are only a couple of webuis using
-  // lottie animations, this update has to be performed manually. As the usage
-  // increases, set this as the default so manual override is no longer
-  // required.
-  html_source->OverrideContentSecurityPolicy(
-      network::mojom::CSPDirectiveName::WorkerSrc,
-      "worker-src blob: chrome://resources 'self';");
-}
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
 void AddSecureDnsStrings(content::WebUIDataSource* html_source) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   const bool kIsRevampEnabled =
diff --git a/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.h b/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.h
index 302a8e2..3d1f528c 100644
--- a/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.h
+++ b/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.h
@@ -29,11 +29,6 @@
 // elements.
 void AddSharedSyncPageStrings(content::WebUIDataSource* html_source);
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-// Adds load time data used by the <settings-nearby-share-subpage>.
-void AddNearbyShareData(content::WebUIDataSource* html_source);
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
 // Adds strings used by the <settings-secure-dns> element.
 void AddSecureDnsStrings(content::WebUIDataSource* html_source);
 }  // namespace settings
diff --git a/chrome/browser/ui/webui/tab_search/tab_search_sync_handler.cc b/chrome/browser/ui/webui/tab_search/tab_search_sync_handler.cc
index c54df49..81f79756 100644
--- a/chrome/browser/ui/webui/tab_search/tab_search_sync_handler.cc
+++ b/chrome/browser/ui/webui/tab_search/tab_search_sync_handler.cc
@@ -33,13 +33,13 @@
 
 void TabSearchSyncHandler::OnJavascriptAllowed() {
   syncer::SyncService* sync_service = GetSyncService();
-  if (sync_service) {
+  if (sync_service && !sync_service_observation_.IsObserving()) {
     sync_service_observation_.Observe(sync_service);
   }
 
   signin::IdentityManager* identity_manager(
       IdentityManagerFactory::GetInstance()->GetForProfile(profile_));
-  if (identity_manager) {
+  if (identity_manager && !identity_manager_observation_.IsObserving()) {
     identity_manager_observation_.Observe(identity_manager);
   }
 }
diff --git a/chrome/renderer/accessibility/read_anything_app_controller.cc b/chrome/renderer/accessibility/read_anything_app_controller.cc
index 0dc7230d..b3c47a9 100644
--- a/chrome/renderer/accessibility/read_anything_app_controller.cc
+++ b/chrome/renderer/accessibility/read_anything_app_controller.cc
@@ -1484,8 +1484,6 @@
 
 int ReadAnythingAppController::GetNextSentence(const std::u16string& text,
                                                int maxTextLength) {
-  // TODO(crbug.com/1474951): Investigate using getting text from the model,
-  // rather than passing it through typescript.
   // TODO(crbug.com/1474941): Investigate providing correct line breaks
   // or alternatively making adjustments to ax_text_utils to return boundaries
   // that minimize choppiness.
diff --git a/chrome/renderer/net/available_offline_content_helper.cc b/chrome/renderer/net/available_offline_content_helper.cc
index 02b46e7..970ebe60 100644
--- a/chrome/renderer/net/available_offline_content_helper.cc
+++ b/chrome/renderer/net/available_offline_content_helper.cc
@@ -11,7 +11,6 @@
 #include "base/json/json_reader.h"
 #include "base/json/json_value_converter.h"
 #include "base/json/json_writer.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/no_destructor.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -71,14 +70,6 @@
   return value;
 }
 
-void RecordSuggestionPresented(
-    const std::vector<AvailableOfflineContentPtr>& suggestions) {
-  for (const AvailableOfflineContentPtr& item : suggestions) {
-    UMA_HISTOGRAM_ENUMERATION("Net.ErrorPageCounts.SuggestionPresented",
-                              item->content_type);
-  }
-}
-
 AvailableOfflineContentHelper::Binder& GetBinderOverride() {
   static base::NoDestructor<AvailableOfflineContentHelper::Binder> binder;
   return *binder;
@@ -167,7 +158,6 @@
     has_prefetched_content_ = fetched_content_.front()->content_type ==
                               AvailableContentType::kPrefetchedPage;
 
-    RecordSuggestionPresented(fetched_content_);
     if (list_visible_by_prefs)
       RecordEvent(error_page::NETWORK_ERROR_PAGE_OFFLINE_SUGGESTIONS_SHOWN);
     else
diff --git a/chrome/renderer/net/net_error_helper_core_unittest.cc b/chrome/renderer/net/net_error_helper_core_unittest.cc
index c1f9f48..538394f 100644
--- a/chrome/renderer/net/net_error_helper_core_unittest.cc
+++ b/chrome/renderer/net/net_error_helper_core_unittest.cc
@@ -1055,14 +1055,6 @@
   EXPECT_TRUE(list_visible_by_prefs());
   EXPECT_EQ(GetExpectedAvailableContentAsJson(), offline_content_json());
 
-  histogram_tester_.ExpectTotalCount("Net.ErrorPageCounts.SuggestionPresented",
-                                     2);
-  histogram_tester_.ExpectBucketCount(
-      "Net.ErrorPageCounts.SuggestionPresented",
-      chrome::mojom::AvailableContentType::kPrefetchedPage, 1);
-  histogram_tester_.ExpectBucketCount(
-      "Net.ErrorPageCounts.SuggestionPresented",
-      chrome::mojom::AvailableContentType::kOtherPage, 1);
   histogram_tester_.ExpectBucketCount(
       "Net.ErrorPageCounts",
       error_page::NETWORK_ERROR_PAGE_OFFLINE_SUGGESTIONS_SHOWN, 1);
@@ -1072,9 +1064,6 @@
 
   core()->LaunchOfflineItem("ID", "name_space");
   histogram_tester_.ExpectBucketCount(
-      "Net.ErrorPageCounts.SuggestionPresented",
-      chrome::mojom::AvailableContentType::kPrefetchedPage, 1);
-  histogram_tester_.ExpectBucketCount(
       "Net.ErrorPageCounts",
       error_page::NETWORK_ERROR_PAGE_OFFLINE_SUGGESTION_CLICKED, 1);
 
@@ -1094,14 +1083,6 @@
   EXPECT_FALSE(list_visible_by_prefs());
   EXPECT_EQ(GetExpectedAvailableContentAsJson(), offline_content_json());
 
-  histogram_tester_.ExpectTotalCount("Net.ErrorPageCounts.SuggestionPresented",
-                                     2);
-  histogram_tester_.ExpectBucketCount(
-      "Net.ErrorPageCounts.SuggestionPresented",
-      chrome::mojom::AvailableContentType::kPrefetchedPage, 1);
-  histogram_tester_.ExpectBucketCount(
-      "Net.ErrorPageCounts.SuggestionPresented",
-      chrome::mojom::AvailableContentType::kOtherPage, 1);
   histogram_tester_.ExpectBucketCount(
       "Net.ErrorPageCounts",
       error_page::NETWORK_ERROR_PAGE_OFFLINE_SUGGESTIONS_SHOWN, 0);
@@ -1111,9 +1092,6 @@
 
   core()->LaunchOfflineItem("ID", "name_space");
   histogram_tester_.ExpectBucketCount(
-      "Net.ErrorPageCounts.SuggestionPresented",
-      chrome::mojom::AvailableContentType::kPrefetchedPage, 1);
-  histogram_tester_.ExpectBucketCount(
       "Net.ErrorPageCounts",
       error_page::NETWORK_ERROR_PAGE_OFFLINE_SUGGESTION_CLICKED, 1);
 
@@ -1149,8 +1127,6 @@
 
   EXPECT_TRUE(list_visible_by_prefs());
   EXPECT_EQ("", offline_content_json());
-  histogram_tester_.ExpectTotalCount("Net.ErrorPageCounts.SuggestionPresented",
-                                     0);
   histogram_tester_.ExpectBucketCount(
       "Net.ErrorPageCounts",
       error_page::NETWORK_ERROR_PAGE_OFFLINE_SUGGESTIONS_SHOWN, 0);
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index cc3ee3e..edd73dd 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1126,8 +1126,6 @@
         "../browser/ash/screenshot_integration_test.cc",
         "../browser/ash/system_web_apps/apps/terminal_integration_test.cc",
         "../browser/ash/web_handwriting_integration_test.cc",
-        "../browser/ui/ash/app_list/app_list_integration_test.cc",
-        "../browser/ui/ash/desks/desks_integration_test.cc",
         "../browser/ui/ash/quick_settings_integration_test.cc",
         "../browser/ui/ash/shelf/shelf_integration_test.cc",
         "base/chromeos/crosier/helper/test_sudo_helper_client_test.cc",
@@ -1135,9 +1133,11 @@
 
         # These cannot live in ":test_support" because they use
         # InProcessBrowserTest which requires HAS_OUT_OF_PROC_TEST_RUNNER.
+        "base/chromeos/crosier/ash_integration_test.cc",
+        "base/chromeos/crosier/ash_integration_test.h",
+        "base/chromeos/crosier/ash_integration_test_test.cc",
         "base/chromeos/crosier/interactive_ash_test.cc",
         "base/chromeos/crosier/interactive_ash_test.h",
-        "base/chromeos/crosier/interactive_ash_test_uitest.cc",
       ]
 
       if (is_chrome_branded) {
@@ -1737,6 +1737,7 @@
       "//chrome/browser/ui/side_panel:side_panel_enums",
       "//chrome/browser/ui/tabs:tab_enums",
       "//chrome/browser/ui/web_applications:browser_tests",
+      "//chrome/browser/ui/webui/privacy_sandbox:mojo_bindings",
       "//chrome/browser/web_applications:browser_tests",
       "//chrome/browser/web_applications:prevent_close_test_support",
       "//chrome/browser/web_applications:web_applications_test_support",
@@ -2812,6 +2813,7 @@
       "../browser/ui/webui/policy/policy_test_ui_browsertest.cc",
       "../browser/ui/webui/policy/policy_ui_browsertest.cc",
       "../browser/ui/webui/prefs_internals_browsertest.cc",
+      "../browser/ui/webui/privacy_sandbox/privacy_sandbox_internals_handler_browsertest.cc",
       "../browser/ui/webui/profile_helper_browsertest.cc",
       "../browser/ui/webui/realbox/realbox_handler_browsertest.cc",
       "../browser/ui/webui/settings/settings_secure_dns_handler_browsertest.cc",
@@ -8262,6 +8264,7 @@
         "//components/app_constants",
         "//components/color",
         "//components/commerce/core:cart_db_content_proto",
+        "//components/commerce/core:commerce_constants",
         "//components/commerce/core:coupon_db_content_proto",
         "//components/commerce/core:shopping_service_test_support",
         "//components/commerce/core/webui:webui",
@@ -11156,11 +11159,9 @@
       }
       if (is_chromeos_ash) {
         sources += [
-          "../browser/ash/bluetooth/bluetooth_integration_test.cc",
           "../browser/ash/file_manager/file_manager_interactive_uitest.cc",
-          "../browser/ui/ash/app_list/app_list_integration_test.cc",
-          "../browser/ui/ash/desks/desks_integration_test.cc",
-          "../browser/ui/ash/quick_settings_integration_test.cc",
+          "../browser/ui/ash/app_list/app_list_interactive_uitest.cc",
+          "../browser/ui/ash/desks/desks_interactive_uitest.cc",
           "../browser/ui/ash/user_education/welcome_tour/welcome_tour_interactive_uitest.cc",
           "../browser/ui/web_applications/test/system_web_app_interactive_uitest.cc",
           "../browser/ui/webui/ash/settings/integration_tests/add_new_keyboard_interactive_uitest.cc",
diff --git a/chrome/test/base/chromeos/crosier/ash_integration_test.cc b/chrome/test/base/chromeos/crosier/ash_integration_test.cc
new file mode 100644
index 0000000..9003dbb
--- /dev/null
+++ b/chrome/test/base/chromeos/crosier/ash_integration_test.cc
@@ -0,0 +1,121 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/test/base/chromeos/crosier/ash_integration_test.h"
+
+#include "ash/constants/ash_switches.h"
+#include "base/check.h"
+#include "base/command_line.h"
+#include "base/environment.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/run_loop.h"
+#include "base/test/test_timeouts.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/base/chromeos/crosier/chromeos_integration_login_mixin.h"
+#include "google_apis/gaia/gaia_switches.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "url/gurl.h"
+
+namespace {
+
+// Simulates a failure for a Gaia URL request.
+std::unique_ptr<net::test_server::HttpResponse> HandleGaiaURL(
+    const net::test_server::HttpRequest& request) {
+  return std::make_unique<net::test_server::HungResponse>();
+}
+
+}  // namespace
+
+AshIntegrationTest::AshIntegrationTest() = default;
+
+AshIntegrationTest::~AshIntegrationTest() = default;
+
+void AshIntegrationTest::SetUpCommandLineForLacros(
+    base::CommandLine* command_line) {
+  CHECK(command_line);
+
+  OverrideGaiaUrlForLacros(command_line);
+
+  // Enable the Wayland server.
+  command_line->AppendSwitch(ash::switches::kAshEnableWaylandServer);
+
+  // Set up XDG_RUNTIME_DIR for Wayland.
+  std::unique_ptr<base::Environment> env(base::Environment::Create());
+  CHECK(scoped_temp_dir_xdg_.CreateUniqueTempDir());
+  env->SetVar("XDG_RUNTIME_DIR", scoped_temp_dir_xdg_.GetPath().AsUTF8Unsafe());
+}
+
+void AshIntegrationTest::WaitForAshFullyStarted() {
+  CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
+      ash::switches::kAshEnableWaylandServer))
+      << "Did you forget to call SetUpCommandLineForLacros?";
+  base::ScopedAllowBlockingForTesting allow_blocking;
+  base::FilePath xdg_path = scoped_temp_dir_xdg_.GetPath();
+  base::RepeatingTimer timer;
+  base::RunLoop run_loop1;
+  timer.Start(FROM_HERE, base::Milliseconds(100),
+              base::BindLambdaForTesting([&]() {
+                if (base::PathExists(xdg_path.Append("wayland-0")) &&
+                    base::PathExists(xdg_path.Append("wayland-0.lock"))) {
+                  run_loop1.Quit();
+                }
+              }));
+  base::ThreadPool::PostDelayedTask(FROM_HERE, run_loop1.QuitClosure(),
+                                    TestTimeouts::action_max_timeout());
+  run_loop1.Run();
+  CHECK(base::PathExists(xdg_path.Append("wayland-0")));
+  CHECK(base::PathExists(xdg_path.Append("wayland-0.lock")));
+
+  // Wait for ChromeBrowserMainExtraParts::PostBrowserStart() to execute so that
+  // crosapi is initialized.
+  auto* extra_parts = ChromeBrowserMainExtraPartsAsh::Get();
+  CHECK(extra_parts);
+  if (!extra_parts->did_post_browser_start()) {
+    base::RunLoop run_loop2;
+    extra_parts->set_post_browser_start_callback(run_loop2.QuitClosure());
+    run_loop2.Run();
+  }
+  CHECK(extra_parts->did_post_browser_start());
+}
+
+void AshIntegrationTest::SetUpOnMainThread() {
+  InteractiveAshTest::SetUpOnMainThread();
+
+  // The embedded test server starts accepting connections after fork.
+  if (https_server_) {
+    https_server_->StartAcceptingConnections();
+  }
+}
+
+void AshIntegrationTest::OverrideGaiaUrlForLacros(
+    base::CommandLine* command_line) {
+  // When using real Gaia login, don't override the Gaia URL.
+  if (login_mixin_.mode() == ChromeOSIntegrationLoginMixin::Mode::kGaiaLogin) {
+    return;
+  }
+
+  // Set up an embedded test server.
+  https_server_ = std::make_unique<net::test_server::EmbeddedTestServer>(
+      net::test_server::EmbeddedTestServer::TYPE_HTTPS);
+  https_server_->RegisterRequestHandler(base::BindRepeating(&HandleGaiaURL));
+  CHECK(https_server_->InitializeAndListen());
+
+  std::vector<std::string> lacros_args;
+  lacros_args.emplace_back(base::StringPrintf("--%s", switches::kNoFirstRun));
+  // Override Gaia url in Lacros so that the gaia requests will NOT be handled
+  // with the real internet connection, but with the embedded test server. The
+  // embedded test server will simulate failure of the Gaia url requests which
+  // is expected in testing environment for Gaia authentication flow. See
+  // crbug.com/1371655.
+  lacros_args.emplace_back(base::StringPrintf(
+      "--%s=%s", switches::kGaiaUrl, https_server_->base_url().spec().c_str()));
+  command_line->AppendSwitchASCII(ash::switches::kLacrosChromeAdditionalArgs,
+                                  base::JoinString(lacros_args, "####"));
+}
diff --git a/chrome/test/base/chromeos/crosier/ash_integration_test.h b/chrome/test/base/chromeos/crosier/ash_integration_test.h
new file mode 100644
index 0000000..7c84d5a2
--- /dev/null
+++ b/chrome/test/base/chromeos/crosier/ash_integration_test.h
@@ -0,0 +1,72 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_TEST_BASE_CHROMEOS_CROSIER_ASH_INTEGRATION_TEST_H_
+#define CHROME_TEST_BASE_CHROMEOS_CROSIER_ASH_INTEGRATION_TEST_H_
+
+#include <memory>
+
+#include "base/files/scoped_temp_dir.h"
+#include "chrome/test/base/chromeos/crosier/chromeos_integration_login_mixin.h"
+#include "chrome/test/base/chromeos/crosier/chromeos_integration_test_mixin.h"
+#include "chrome/test/base/chromeos/crosier/interactive_ash_test.h"
+
+namespace base {
+class CommandLine;
+}
+
+namespace net::test_server {
+class EmbeddedTestServer;
+}
+
+// Base class for tests of ash-chrome integration with the ChromeOS platform,
+// like hardware daemons, graphics, kernel, etc.
+//
+// Tests using this base class should be added to "chromeos_integration_tests"
+// and will run on devices under test (DUTs) and virtual machines (VMs).
+//
+// Because this class derives from InProcessBrowserTest the source files must be
+// added to a target that defines HAS_OUT_OF_PROC_TEST_RUNNER. The source files
+// cannot be in a shared test support target that lacks that define.
+class AshIntegrationTest : public InteractiveAshTest {
+ public:
+  AshIntegrationTest();
+  AshIntegrationTest(const AshIntegrationTest&) = delete;
+  AshIntegrationTest& operator=(const AshIntegrationTest&) = delete;
+  ~AshIntegrationTest() override;
+
+  // Sets up the command line and environment variables to support Lacros (by
+  // enabling the Wayland server in ash). Call this from SetUpCommandLine() if
+  // your test starts Lacros.
+  void SetUpCommandLineForLacros(base::CommandLine* command_line);
+
+  // Waits for Ash to be ready for Lacros, including starting the "Exo" Wayland
+  // server. Call this method if your test starts Lacros, otherwise Exo may not
+  // be ready and Lacros may not start.
+  void WaitForAshFullyStarted();
+
+  // MixinBasedInProcessBrowserTest:
+  void SetUpOnMainThread() override;
+
+  ChromeOSIntegrationLoginMixin& login_mixin() { return login_mixin_; }
+
+ private:
+  // Overrides the Gaia URL to point to a local test server that produces an
+  // error, which is expected behavior in test environments.
+  void OverrideGaiaUrlForLacros(base::CommandLine* command_line);
+
+  // This test runs on linux-chromeos in interactive_ui_tests and on a DUT in
+  // chromeos_integration_tests.
+  ChromeOSIntegrationTestMixin chromeos_integration_test_mixin_{&mixin_host_};
+
+  // Login support.
+  ChromeOSIntegrationLoginMixin login_mixin_{&mixin_host_};
+
+  // Directory used by Wayland/Lacros in environment variable XDG_RUNTIME_DIR.
+  base::ScopedTempDir scoped_temp_dir_xdg_;
+
+  std::unique_ptr<net::test_server::EmbeddedTestServer> https_server_;
+};
+
+#endif  // CHROME_TEST_BASE_CHROMEOS_CROSIER_ASH_INTEGRATION_TEST_H_
diff --git a/chrome/test/base/chromeos/crosier/ash_integration_test_test.cc b/chrome/test/base/chromeos/crosier/ash_integration_test_test.cc
new file mode 100644
index 0000000..36dafda7
--- /dev/null
+++ b/chrome/test/base/chromeos/crosier/ash_integration_test_test.cc
@@ -0,0 +1,41 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/test/base/chromeos/crosier/ash_integration_test.h"
+#include "url/gurl.h"
+
+namespace ash {
+namespace {
+
+class AshIntegrationTestTest : public AshIntegrationTest {
+ public:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    InteractiveAshTest::SetUpCommandLine(command_line);
+    SetUpCommandLineForLacros(command_line);
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(AshIntegrationTestTest, Basics) {
+  SetupContextWidget();
+
+  // Verify that installing system apps doesn't crash or flake.
+  InstallSystemApps();
+
+  // Verify that the Wayland server starts and doesn't crash or flake.
+  WaitForAshFullyStarted();
+
+  // Verify an active user exists.
+  ASSERT_TRUE(GetActiveUserProfile());
+
+  // Open a browser window.
+  GURL version_url("chrome://version");
+  ASSERT_TRUE(CreateBrowserWindow(version_url));
+
+  // Open a second browser window.
+  GURL blank_url("about:blank");
+  ASSERT_TRUE(CreateBrowserWindow(blank_url));
+}
+
+}  // namespace
+}  // namespace ash
diff --git a/chrome/test/base/chromeos/crosier/interactive_ash_test.cc b/chrome/test/base/chromeos/crosier/interactive_ash_test.cc
index 2887af7..ca08a31 100644
--- a/chrome/test/base/chromeos/crosier/interactive_ash_test.cc
+++ b/chrome/test/base/chromeos/crosier/interactive_ash_test.cc
@@ -4,36 +4,21 @@
 
 #include "chrome/test/base/chromeos/crosier/interactive_ash_test.h"
 
-#include "ash/constants/ash_switches.h"
 #include "ash/root_window_controller.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
 #include "base/check.h"
 #include "base/command_line.h"
-#include "base/environment.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
 #include "base/functional/bind.h"
 #include "base/json/string_escape.h"
 #include "base/test/test_switches.h"
-#include "base/test/test_timeouts.h"
-#include "base/threading/thread_restrictions.h"
-#include "base/time/time.h"
-#include "base/timer/timer.h"
 #include "chrome/browser/ash/app_restore/full_restore_app_launch_handler.h"
 #include "chrome/browser/ash/system_web_apps/system_web_app_manager.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_navigator.h"
-#include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/chromeos/crosier/aura_window_title_observer.h"
-#include "chrome/test/base/chromeos/crosier/chromeos_integration_login_mixin.h"
-#include "google_apis/gaia/gaia_switches.h"
-#include "net/test/embedded_test_server/embedded_test_server.h"
-#include "net/test/embedded_test_server/http_response.h"
-#include "ui/aura/test/find_window.h"
 #include "url/gurl.h"
 
 namespace {
@@ -41,14 +26,6 @@
 using InteractiveMixinBasedBrowserTest =
     InteractiveBrowserTestT<MixinBasedInProcessBrowserTest>;
 
-#if BUILDFLAG(IS_CHROMEOS_DEVICE)
-// Simulates a failure for a Gaia URL request.
-std::unique_ptr<net::test_server::HttpResponse> HandleGaiaURL(
-    const net::test_server::HttpRequest& request) {
-  return std::make_unique<net::test_server::HungResponse>();
-}
-#endif  // BUILDFLAG(IS_CHROMEOS_DEVICE)
-
 }  // namespace
 
 InteractiveAshTest::InteractiveAshTest() {
@@ -98,65 +75,6 @@
   return Navigate(&params);
 }
 
-void InteractiveAshTest::SetUpCommandLineForLacros(
-    base::CommandLine* command_line) {
-  CHECK(command_line);
-
-#if BUILDFLAG(IS_CHROMEOS_DEVICE)
-  OverrideGaiaUrlForLacros(command_line);
-#endif
-
-  // Enable the Wayland server.
-  command_line->AppendSwitch(ash::switches::kAshEnableWaylandServer);
-
-  // Set up XDG_RUNTIME_DIR for Wayland.
-  std::unique_ptr<base::Environment> env(base::Environment::Create());
-  CHECK(scoped_temp_dir_xdg_.CreateUniqueTempDir());
-  env->SetVar("XDG_RUNTIME_DIR", scoped_temp_dir_xdg_.GetPath().AsUTF8Unsafe());
-}
-
-void InteractiveAshTest::WaitForAshFullyStarted() {
-  CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
-      ash::switches::kAshEnableWaylandServer))
-      << "Did you forget to call SetUpCommandLineForLacros?";
-  base::ScopedAllowBlockingForTesting allow_blocking;
-  base::FilePath xdg_path = scoped_temp_dir_xdg_.GetPath();
-  base::RepeatingTimer timer;
-  base::RunLoop run_loop1;
-  timer.Start(FROM_HERE, base::Milliseconds(100),
-              base::BindLambdaForTesting([&]() {
-                if (base::PathExists(xdg_path.Append("wayland-0")) &&
-                    base::PathExists(xdg_path.Append("wayland-0.lock"))) {
-                  run_loop1.Quit();
-                }
-              }));
-  base::ThreadPool::PostDelayedTask(FROM_HERE, run_loop1.QuitClosure(),
-                                    TestTimeouts::action_max_timeout());
-  run_loop1.Run();
-  CHECK(base::PathExists(xdg_path.Append("wayland-0")));
-  CHECK(base::PathExists(xdg_path.Append("wayland-0.lock")));
-
-  // Wait for ChromeBrowserMainExtraParts::PostBrowserStart() to execute so that
-  // crosapi is initialized.
-  auto* extra_parts = ChromeBrowserMainExtraPartsAsh::Get();
-  CHECK(extra_parts);
-  if (!extra_parts->did_post_browser_start()) {
-    base::RunLoop run_loop2;
-    extra_parts->set_post_browser_start_callback(run_loop2.QuitClosure());
-    run_loop2.Run();
-  }
-  CHECK(extra_parts->did_post_browser_start());
-}
-
-void InteractiveAshTest::SetUpOnMainThread() {
-  InteractiveBrowserTestT<MixinBasedInProcessBrowserTest>::SetUpOnMainThread();
-
-  // The embedded test server starts accepting connections after fork.
-  if (https_server_) {
-    https_server_->StartAcceptingConnections();
-  }
-}
-
 void InteractiveAshTest::TearDownOnMainThread() {
   // Passing --test-launcher-interactive leaves the browser running after the
   // end of the test.
@@ -219,31 +137,3 @@
   state_change.event = kTextFound;
   return WaitForStateChange(element_id, state_change);
 }
-
-#if BUILDFLAG(IS_CHROMEOS_DEVICE)
-void InteractiveAshTest::OverrideGaiaUrlForLacros(
-    base::CommandLine* command_line) {
-  // When using real Gaia login, don't override the Gaia URL.
-  if (login_mixin_.mode() == ChromeOSIntegrationLoginMixin::Mode::kGaiaLogin) {
-    return;
-  }
-
-  // Set up an embedded test server.
-  https_server_ = std::make_unique<net::test_server::EmbeddedTestServer>(
-      net::test_server::EmbeddedTestServer::TYPE_HTTPS);
-  https_server_->RegisterRequestHandler(base::BindRepeating(&HandleGaiaURL));
-  CHECK(https_server_->InitializeAndListen());
-
-  std::vector<std::string> lacros_args;
-  lacros_args.emplace_back(base::StringPrintf("--%s", switches::kNoFirstRun));
-  // Override Gaia url in Lacros so that the gaia requests will NOT be handled
-  // with the real internet connection, but with the embedded test server. The
-  // embedded test server will simulate failure of the Gaia url requests which
-  // is expected in testing environment for Gaia authentication flow. See
-  // crbug.com/1371655.
-  lacros_args.emplace_back(base::StringPrintf(
-      "--%s=%s", switches::kGaiaUrl, https_server_->base_url().spec().c_str()));
-  command_line->AppendSwitchASCII(ash::switches::kLacrosChromeAdditionalArgs,
-                                  base::JoinString(lacros_args, "####"));
-}
-#endif  // BUILDFLAG(IS_CHROMEOS_DEVICE)
diff --git a/chrome/test/base/chromeos/crosier/interactive_ash_test.h b/chrome/test/base/chromeos/crosier/interactive_ash_test.h
index 89d1b57..c8e21c6 100644
--- a/chrome/test/base/chromeos/crosier/interactive_ash_test.h
+++ b/chrome/test/base/chromeos/crosier/interactive_ash_test.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/files/scoped_temp_dir.h"
 #include "base/memory/weak_ptr.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/test/base/mixin_based_in_process_browser_test.h"
@@ -15,45 +14,25 @@
 #include "content/public/test/browser_test.h"
 #include "ui/base/interaction/interaction_sequence.h"
 
-#if BUILDFLAG(IS_CHROMEOS_DEVICE)
-#include "chrome/test/base/chromeos/crosier/chromeos_integration_login_mixin.h"
-#include "chrome/test/base/chromeos/crosier/chromeos_integration_test_mixin.h"
-#endif
-
 class GURL;
 class Profile;
 
-namespace base {
-class CommandLine;
-}
-
 namespace content {
 class NavigationHandle;
 }
 
-namespace net::test_server {
-class EmbeddedTestServer;
-}
-
-// Base class for tests of ash-chrome integration with the ChromeOS platform,
-// like hardware daemons, graphics, kernel, etc.
-//
 // Sets up Kombucha for ash testing:
 // - Provides 1 Kombucha "context" per display, shared by all views::Widgets
 // - Provides a default "context widget" so Kombucha can synthesize mouse events
 // - Suppresses creating a browser window on startup, because most ash-chrome
 //   tests don't need the window and creating it slows down the test
 //
-// Tests using this base class can be added to "chromeos_integration_tests" to
-// run on devices under test (DUTs) and virtual machines (VMs). Also, if a test
-// only communicates with OS daemons via D-Bus then the test can also run in the
-// linux-chromeos "emulator" in "interactive_ui_tests". The latter approach
-// makes it simpler to write the initial version of a test, which can then be
-// added to "chromeos_integration_tests" to also run on DUT/VM.
-//
 // Because this class derives from InProcessBrowserTest the source files must be
 // added to a target that defines HAS_OUT_OF_PROC_TEST_RUNNER. The source files
 // cannot be in a shared test support target that lacks that define.
+//
+// For tests that run on a DUT or in a VM, use the subclass AshIntegrationTest,
+// which supports running on hardware.
 class InteractiveAshTest
     : public InteractiveBrowserTestT<MixinBasedInProcessBrowserTest> {
  public:
@@ -82,20 +61,7 @@
   // browser_navigator.h.
   base::WeakPtr<content::NavigationHandle> CreateBrowserWindow(const GURL& url);
 
-  // Sets up the command line and environment variables to support Lacros (by
-  // enabling the Wayland server in ash). Call this from SetUpCommandLine() if
-  // your test starts Lacros.
-  void SetUpCommandLineForLacros(base::CommandLine* command_line);
-
-  // Waits for Ash to be ready for Lacros, including starting the "Exo" Wayland
-  // server. Call this method if your test starts Lacros, otherwise Exo may not
-  // be ready and Lacros may not start.
-  // TODO(http://b/297930282): Ensure we compile ToT Lacros and use it when
-  // testing ToT ash. The rootfs Lacros may be too old to run with ToT ash.
-  void WaitForAshFullyStarted();
-
   // MixinBasedInProcessBrowserTest:
-  void SetUpOnMainThread() override;
   void TearDownOnMainThread() override;
 
   // Blocks until a window exists with the given title. If a matching window
@@ -116,10 +82,6 @@
   WaitForElementDoesNotExist(const ui::ElementIdentifier& element_id,
                              const DeepQuery& query);
 
-#if BUILDFLAG(IS_CHROMEOS_DEVICE)
-  ChromeOSIntegrationLoginMixin& login_mixin() { return login_mixin_; }
-#endif
-
   // Waits until the element or any of its children have the requested text.
   //
   // element_id
@@ -136,24 +98,6 @@
       const ui::ElementIdentifier& element_id,
       const WebContentsInteractionTestUtil::DeepQuery& query,
       const std::string& expected);
-
- private:
-#if BUILDFLAG(IS_CHROMEOS_DEVICE)
-  // Overrides the Gaia URL to point to a local test server that produces an
-  // error, which is expected behavior in test environments.
-  void OverrideGaiaUrlForLacros(base::CommandLine* command_line);
-
-  // This test runs on linux-chromeos in interactive_ui_tests and on a DUT in
-  // chromeos_integration_tests.
-  ChromeOSIntegrationTestMixin chromeos_integration_test_mixin_{&mixin_host_};
-
-  // Login support.
-  ChromeOSIntegrationLoginMixin login_mixin_{&mixin_host_};
-#endif
-
-  // Directory used by Wayland/Lacros in environment variable XDG_RUNTIME_DIR.
-  base::ScopedTempDir scoped_temp_dir_xdg_;
-
-  std::unique_ptr<net::test_server::EmbeddedTestServer> https_server_;
 };
+
 #endif  // CHROME_TEST_BASE_CHROMEOS_CROSIER_INTERACTIVE_ASH_TEST_H_
diff --git a/chrome/test/base/chromeos/crosier/interactive_ash_test_uitest.cc b/chrome/test/base/chromeos/crosier/interactive_ash_test_uitest.cc
index b9f2810..af05fc13 100644
--- a/chrome/test/base/chromeos/crosier/interactive_ash_test_uitest.cc
+++ b/chrome/test/base/chromeos/crosier/interactive_ash_test_uitest.cc
@@ -8,13 +8,7 @@
 namespace ash {
 namespace {
 
-class InteractiveAshTestUITest : public InteractiveAshTest {
- public:
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    InteractiveAshTest::SetUpCommandLine(command_line);
-    SetUpCommandLineForLacros(command_line);
-  }
-};
+using InteractiveAshTestUITest = InteractiveAshTest;
 
 // TODO(crbug.com/1511507): Re-enable this test
 IN_PROC_BROWSER_TEST_F(InteractiveAshTestUITest, DISABLED_Basics) {
@@ -23,9 +17,6 @@
   // Verify that installing system apps doesn't crash or flake.
   InstallSystemApps();
 
-  // Verify that the Wayland server starts and doesn't crash or flake.
-  WaitForAshFullyStarted();
-
   // Verify an active user exists.
   ASSERT_TRUE(GetActiveUserProfile());
 
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index 7458e52..17f04b9 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -94,12 +94,13 @@
 
   if (is_chromeos_ash) {
     sources += [
+      "chromeos/ash_common/sea_pen/sea_pen_browsertest.cc",
       "chromeos/ash_common/webui_resource_browsertest.cc",
       "chromeos/enterprise_reporting/enterprise_reporting_browsertest.cc",
       "chromeos/firmware_update/firmware_update_browsertest.cc",
       "chromeos/inline_login/inline_login_browsertest.cc",
       "chromeos/personalization_app/personalization_app_browsertest.cc",
-      "chromeos/personalization_app/sea_pen_browsertest.cc",
+      "chromeos/personalization_app/personalization_app_sea_pen_browsertest.cc",
       "chromeos/scanning/scanning_app_browsertest.cc",
       "chromeos/vc_background_ui/vc_background_ui_browsertest.cc",
     ]
diff --git a/chrome/test/data/webui/chromeos/ash_common/BUILD.gn b/chrome/test/data/webui/chromeos/ash_common/BUILD.gn
index 003f1c0..94b9a8f 100644
--- a/chrome/test/data/webui/chromeos/ash_common/BUILD.gn
+++ b/chrome/test/data/webui/chromeos/ash_common/BUILD.gn
@@ -31,6 +31,7 @@
     "post_message_api/post_message_api_test.js",
     "shortcut_input_key_test.ts",
     "shortcut_input_test.ts",
+    "sea_pen/sea_pen_utils_test.ts",
     "typescript_utils/strict_query_test.ts",
   ]
   deps = [
diff --git a/chrome/test/data/webui/chromeos/ash_common/sea_pen/sea_pen_browsertest.cc b/chrome/test/data/webui/chromeos/ash_common/sea_pen/sea_pen_browsertest.cc
new file mode 100644
index 0000000..dad79ae
--- /dev/null
+++ b/chrome/test/data/webui/chromeos/ash_common/sea_pen/sea_pen_browsertest.cc
@@ -0,0 +1,12 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/test/base/web_ui_mocha_browser_test.h"
+#include "content/public/test/browser_test.h"
+
+using SeaPenBrowserTest = WebUIMochaBrowserTest;
+
+IN_PROC_BROWSER_TEST_F(SeaPenBrowserTest, SeaPenUtils) {
+  RunTest("chromeos/ash_common/sea_pen/sea_pen_utils_test.js", "mocha.run()");
+}
diff --git a/chrome/test/data/webui/chromeos/ash_common/sea_pen/sea_pen_utils_test.ts b/chrome/test/data/webui/chromeos/ash_common/sea_pen/sea_pen_utils_test.ts
new file mode 100644
index 0000000..dcc4f1dd
--- /dev/null
+++ b/chrome/test/data/webui/chromeos/ash_common/sea_pen/sea_pen_utils_test.ts
@@ -0,0 +1,49 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {isImageDataUrl, isNonEmptyFilePath} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js';
+import {assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
+
+suite('isImageDataUrlTest', function() {
+  test('invalid types', function() {
+    for (const value of [null, undefined, false, 'not_url', 0, 1, {}]) {
+      assertFalse(isImageDataUrl(value), `${value} is not Url`);
+    }
+  });
+
+  test('Url but not image data Url', function() {
+    assertFalse(isImageDataUrl(
+        {url: 'data:text/html,%3Ch1%3EHello%2C%20World%21%3C%2Fh1%3E'}));
+  });
+
+  test('image data url with invalid jpg type', function() {
+    assertFalse(
+        isImageDataUrl({url: 'data:image/jpg;base64,a'}),
+        'image/jpg should be image/jpeg');
+  });
+
+  test('valid image data url', function() {
+    assertTrue(isImageDataUrl({url: 'data:image/jpeg;base64,a'}));
+    assertTrue(isImageDataUrl({url: 'data:image/png;base64,a'}));
+  });
+});
+
+suite('isNonEmptyFilePathTest', function() {
+  test('invalid types', function() {
+    for (const value of [null, undefined, false, 'not_file_path', 0, 1, {}]) {
+      assertFalse(isNonEmptyFilePath(value), `${value} is not FilePath`);
+    }
+  });
+
+  test('empty path', function() {
+    assertFalse(isNonEmptyFilePath({path: null}), 'null path invalid');
+    assertFalse(
+        isNonEmptyFilePath({path: undefined}), 'undefined path invalid');
+    assertFalse(isNonEmptyFilePath({path: ''}), 'empty path invalid');
+  });
+
+  test('Non-empty path', function() {
+    assertTrue(isNonEmptyFilePath({path: 'a'}));
+  });
+});
diff --git a/chrome/test/data/webui/chromeos/personalization_app/personalization_app_controller_test.ts b/chrome/test/data/webui/chromeos/personalization_app/personalization_app_controller_test.ts
index e01ed62..bc7ca19d 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/personalization_app_controller_test.ts
+++ b/chrome/test/data/webui/chromeos/personalization_app/personalization_app_controller_test.ts
@@ -4,7 +4,8 @@
 
 import 'chrome://personalization/strings.m.js';
 
-import {cancelPreviewWallpaper, DailyRefreshType, DefaultImageSymbol, DisplayableImage, fetchCollections, fetchGooglePhotosAlbum, fetchGooglePhotosAlbums, fetchGooglePhotosEnabled, fetchGooglePhotosPhotos, fetchLocalData, getDefaultImageThumbnail, GooglePhotosEnablementState, GooglePhotosPhoto, initializeBackdropData, isDefaultImage, isFilePath, isGooglePhotosPhoto, isWallpaperImage, kDefaultImageSymbol, selectGooglePhotosAlbum, selectWallpaper, setDailyRefreshCollectionId, updateDailyRefreshWallpaper, WallpaperLayout, WallpaperObserver, WallpaperType} from 'chrome://personalization/js/personalization_app.js';
+import {cancelPreviewWallpaper, DailyRefreshType, DefaultImageSymbol, DisplayableImage, fetchCollections, fetchGooglePhotosAlbum, fetchGooglePhotosAlbums, fetchGooglePhotosEnabled, fetchGooglePhotosPhotos, fetchLocalData, getDefaultImageThumbnail, GooglePhotosEnablementState, GooglePhotosPhoto, initializeBackdropData, isDefaultImage, isGooglePhotosPhoto, isWallpaperImage, kDefaultImageSymbol, selectGooglePhotosAlbum, selectWallpaper, setDailyRefreshCollectionId, updateDailyRefreshWallpaper, WallpaperLayout, WallpaperObserver, WallpaperType} from 'chrome://personalization/js/personalization_app.js';
+import {isNonEmptyFilePath} from 'chrome://resources/ash/common/sea_pen/sea_pen_utils.js';
 import {assertNotReached} from 'chrome://resources/js/assert.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
 import {FilePath} from 'chrome://resources/mojo/mojo/public/mojom/base/file_path.mojom-webui.js';
@@ -24,7 +25,7 @@
   if (isWallpaperImage(image)) {
     return image.unitId.toString();
   }
-  if (isFilePath(image)) {
+  if (isNonEmptyFilePath(image)) {
     return image.path;
   }
   assertNotReached('unknown wallpaper type');
@@ -873,7 +874,7 @@
     if (isWallpaperImage(image)) {
       return WallpaperType.kOnline;
     }
-    if (isFilePath(image)) {
+    if (isNonEmptyFilePath(image)) {
       return WallpaperType.kCustomized;
     }
     assertNotReached('unknown wallpaper type');
@@ -997,7 +998,7 @@
         'wallpaper.local.images is not array');
     assertTrue(
         personalizationStore.data.wallpaper.local.images.every(
-            (image: FilePath|DefaultImageSymbol) => isFilePath(image) &&
+            (image: FilePath|DefaultImageSymbol) => isNonEmptyFilePath(image) &&
                 !!personalizationStore.data.wallpaper.local.data[image.path]),
         'every image is file path with data');
 
diff --git a/chrome/test/data/webui/chromeos/personalization_app/sea_pen_browsertest.cc b/chrome/test/data/webui/chromeos/personalization_app/personalization_app_sea_pen_browsertest.cc
similarity index 89%
rename from chrome/test/data/webui/chromeos/personalization_app/sea_pen_browsertest.cc
rename to chrome/test/data/webui/chromeos/personalization_app/personalization_app_sea_pen_browsertest.cc
index 51a7a95..d4f651d2 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/sea_pen_browsertest.cc
+++ b/chrome/test/data/webui/chromeos/personalization_app/personalization_app_sea_pen_browsertest.cc
@@ -5,6 +5,8 @@
 #include "ash/webui/personalization_app/test/personalization_app_mojom_banned_mocha_test_base.h"
 #include "content/public/test/browser_test.h"
 
+// TODO(b/312208348) move this test to ash common sea_pen browsertest.
+
 namespace ash::personalization_app {
 
 // Tests state management and logic in SeaPen.
diff --git a/chrome/test/data/webui/settings/OWNERS b/chrome/test/data/webui/settings/OWNERS
index 69e0e85b..7ae1111 100644
--- a/chrome/test/data/webui/settings/OWNERS
+++ b/chrome/test/data/webui/settings/OWNERS
@@ -1,7 +1,7 @@
 file://chrome/browser/resources/settings/OWNERS
 
 per-file collapse_radio_button_tests.ts=sauski@google.com
-per-file cookies_page_test.ts=sauski@google.com,rainhard@chromium.org
+per-file cookies_page_test.ts=fmacintosh@google.com,sauski@google.com,rainhard@chromium.org
 per-file clear_browsing_data_test.ts=sauski@google.com
 per-file do_not_track_toggle_test.ts=sauski@google.com
 per-file do_not_track_toggle_test.ts=sauski@google.com
diff --git a/chrome/test/data/webui/settings/chromeos/crostini_page/crostini_extra_containers_subpage_test.ts b/chrome/test/data/webui/settings/chromeos/crostini_page/crostini_extra_containers_subpage_test.ts
index d00c85e..5379dbb 100644
--- a/chrome/test/data/webui/settings/chromeos/crostini_page/crostini_extra_containers_subpage_test.ts
+++ b/chrome/test/data/webui/settings/chromeos/crostini_page/crostini_extra_containers_subpage_test.ts
@@ -4,11 +4,10 @@
 
 import 'chrome://os-settings/lazy_load.js';
 
-import {ContainerInfo, CrostiniBrowserProxyImpl, ExtraContainersCreateDialog, ExtraContainersElement, SettingsCrostiniPageElement} from 'chrome://os-settings/lazy_load.js';
+import {ContainerInfo, CrostiniBrowserProxyImpl, ExtraContainersCreateDialog, ExtraContainersElement} from 'chrome://os-settings/lazy_load.js';
 import {CrInputElement, CrToggleElement, IronCollapseElement, Router, routes} from 'chrome://os-settings/os_settings.js';
 import {webUIListenerCallback} from 'chrome://resources/js/cr.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
-import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {assertArrayEquals, assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
 import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
 import {disableAnimationsAndTransitions} from 'chrome://webui-test/test_api.js';
@@ -16,17 +15,14 @@
 import {SharedVmDevices, TestCrostiniBrowserProxy} from './test_crostini_browser_proxy.js';
 
 suite('<settings-crostini-extra-containers>', () => {
-  let crostiniPage: SettingsCrostiniPageElement;
   let crostiniBrowserProxy: TestCrostiniBrowserProxy;
   let subpage: ExtraContainersElement;
 
-  setup(async () => {
-    crostiniBrowserProxy = new TestCrostiniBrowserProxy();
-    CrostiniBrowserProxyImpl.setInstanceForTesting(crostiniBrowserProxy);
-    crostiniPage = document.createElement('settings-crostini-page');
-    document.body.appendChild(crostiniPage);
+  suiteSetup(() => {
     disableAnimationsAndTransitions();
+  });
 
+  setup(async () => {
     const allContainers: ContainerInfo[] = [
       {
         id: {container_name: 'penguin', vm_name: 'termina'},
@@ -57,36 +53,31 @@
       },
     ];
 
+    crostiniBrowserProxy = new TestCrostiniBrowserProxy();
+    CrostiniBrowserProxyImpl.setInstanceForTesting(crostiniBrowserProxy);
     crostiniBrowserProxy.containerInfo = allContainers;
     crostiniBrowserProxy.sharedVmDevices = sharedVmDevices;
-    crostiniPage.prefs = {
+
+    Router.getInstance().navigateTo(routes.CROSTINI_EXTRA_CONTAINERS);
+
+    subpage = document.createElement('settings-crostini-extra-containers');
+    subpage.prefs = {
       crostini: {
         enabled: {value: true},
       },
     };
-    flush();
-
-    assertEquals(0, crostiniBrowserProxy.getCallCount('requestContainerInfo'));
-    assertEquals(
-        0, crostiniBrowserProxy.getCallCount('requestSharedVmDevices'));
-
-    Router.getInstance().navigateTo(routes.CROSTINI_EXTRA_CONTAINERS);
-
+    document.body.appendChild(subpage);
     await flushTasks();
-    const subpageElement =
-        crostiniPage.shadowRoot!.querySelector<ExtraContainersElement>(
-            'settings-crostini-extra-containers');
-    assertTrue(!!subpageElement);
-    subpage = subpageElement;
-    assertTrue(!!subpage);
+
     assertEquals(1, crostiniBrowserProxy.getCallCount('requestContainerInfo'));
     assertEquals(
         1, crostiniBrowserProxy.getCallCount('requestSharedVmDevices'));
   });
 
   teardown(() => {
-    crostiniPage.remove();
+    subpage.remove();
     Router.getInstance().resetRouteForTesting();
+    crostiniBrowserProxy.reset();
   });
 
   suite('CreateContainerDialog', () => {
diff --git a/chrome/test/data/webui/settings/chromeos/device_page/display_page_test.ts b/chrome/test/data/webui/settings/chromeos/device_page/display_page_test.ts
index 85c7e72..93140c2f 100644
--- a/chrome/test/data/webui/settings/chromeos/device_page/display_page_test.ts
+++ b/chrome/test/data/webui/settings/chromeos/device_page/display_page_test.ts
@@ -4,7 +4,7 @@
 
 import 'chrome://os-settings/lazy_load.js';
 
-import {CrLinkRowElement, DevicePageBrowserProxyImpl, displaySettingsProviderMojom, Router, routes, setDisplayApiForTesting, setDisplaySettingsProviderForTesting, SettingsDisplayElement, SettingsSliderElement} from 'chrome://os-settings/os_settings.js';
+import {CrLinkRowElement, DevicePageBrowserProxyImpl, displaySettingsProviderMojom, Router, routes, setDisplayApiForTesting, setDisplaySettingsProviderForTesting, SettingsDisplayElement, SettingsDropdownMenuElement, SettingsSliderElement, SettingsToggleButtonElement} from 'chrome://os-settings/os_settings.js';
 import {strictQuery} from 'chrome://resources/ash/common/typescript_utils/strict_query.js';
 import {getDeepActiveElement} from 'chrome://resources/ash/common/util.js';
 import {assert} from 'chrome://resources/js/assert.js';
@@ -20,6 +20,8 @@
 
 import DisplayUnitInfo = chrome.system.display.DisplayUnitInfo;
 
+const kDisplayIdPrefix = '123456789';
+
 suite('<settings-display>', () => {
   let displayPage: SettingsDisplayElement;
   let fakeSystemDisplay: FakeSystemDisplay;
@@ -29,7 +31,7 @@
   // Add a fake display.
   function addDisplay(displayIndex: number): void {
     const display = {
-      id: 'fakeDisplayId' + displayIndex,
+      id: kDisplayIdPrefix + displayIndex,
       name: 'fakeDisplayName' + displayIndex,
       mirroring: '',
       isPrimary: displayIndex === 1,
@@ -161,8 +163,8 @@
     const displayLayout =
         displayPage.shadowRoot!.querySelector('#displayLayout');
     assertTrue(!!displayLayout);
-    const displayDiv =
-        strictQuery('#_fakeDisplayId2', displayLayout.shadowRoot, HTMLElement);
+    const displayDiv = strictQuery(
+        `#_${kDisplayIdPrefix}2`, displayLayout.shadowRoot, HTMLElement);
     assertTrue(!!displayDiv);
     displayDiv.click();
 
@@ -266,6 +268,40 @@
         1,
         externalDisplayHistogram.get(
             displaySettingsProviderMojom.DisplaySettingsType.kOverscan));
+
+    // Mock user toggling night light button.
+    const displayNightLight = strictQuery(
+        'settings-display-night-light', displayPage.shadowRoot, HTMLElement);
+    assertTrue(!!displayNightLight);
+    const nightLightToggleButton =
+        displayNightLight.shadowRoot!.getElementById(
+            'nightLightToggleButton') as SettingsToggleButtonElement;
+    assertTrue(!!nightLightToggleButton);
+    nightLightToggleButton.click();
+    flush();
+
+    // Verify histogram count for night light setting.
+    assertEquals(
+        1,
+        externalDisplayHistogram.get(
+            displaySettingsProviderMojom.DisplaySettingsType.kNightLight));
+
+    // Mock user updating night light schedule.
+    const schedule =
+        displayNightLight.shadowRoot!.getElementById(
+            'nightLightScheduleTypeDropDown') as SettingsDropdownMenuElement;
+    schedule.pref = {
+      key: 'ash.night_light.schedule_type',
+      type: chrome.settingsPrivate.PrefType.NUMBER,
+      value: 1,
+    };
+
+    // Verify histogram count for night light setting.
+    assertEquals(
+        1,
+        externalDisplayHistogram.get(
+            displaySettingsProviderMojom.DisplaySettingsType
+                .kNightLightSchedule));
   });
 
   test('display tests', async function() {
@@ -397,7 +433,7 @@
               displayPage.shadowRoot!.querySelector('#displayLayout');
           assertTrue(!!displayLayout);
           const displayDiv = strictQuery(
-              '#_fakeDisplayId2', displayLayout.shadowRoot, HTMLElement);
+              `#_${kDisplayIdPrefix}2`, displayLayout.shadowRoot, HTMLElement);
           assertTrue(!!displayDiv);
           displayDiv.click();
           assertEquals(
@@ -568,10 +604,11 @@
               displayPage.shadowRoot!.querySelector('#displayLayout') as any;
           assert(!!displayLayout);
           const display = strictQuery(
-              '#_fakeDisplayId2', displayLayout.shadowRoot, HTMLElement);
-          const layout = displayLayout.displayLayoutMap_.get('fakeDisplayId2');
+              `#_${kDisplayIdPrefix}2`, displayLayout.shadowRoot, HTMLElement);
+          const layout =
+              displayLayout.displayLayoutMap_.get(`${kDisplayIdPrefix}2`);
 
-          assertEquals(layout.parentId, 'fakeDisplayId1');
+          assertEquals(layout.parentId, `${kDisplayIdPrefix}1`);
           assertEquals(layout.position, 'right');
 
           const offset =
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
index 3ad2c959..07bc3e3d 100644
--- a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
@@ -240,6 +240,24 @@
       mocha.run();
     });
 
+var OSSettingsCrostiniPageCrostiniExtraContainersSubpageRevampTest =
+    class extends OSSettingsCrostiniPageCrostiniExtraContainersSubpageTest {
+  /** @override */
+  get featureList() {
+    return {
+      enabled: super.featureList.enabled.concat([
+        'ash::features::kOsSettingsRevampWayfinding',
+      ]),
+    };
+  }
+};
+
+TEST_F(
+    'OSSettingsCrostiniPageCrostiniExtraContainersSubpageRevampTest',
+    'AllJsTests', () => {
+      mocha.run();
+    });
+
 var OSSettingsCrostiniPageTest = class extends OSSettingsBrowserTest {
   /** @override */
   get browsePreload() {
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/wallpaper_search/combobox_test.ts b/chrome/test/data/webui/side_panel/customize_chrome/wallpaper_search/combobox_test.ts
index 481f55e..e243096 100644
--- a/chrome/test/data/webui/side_panel/customize_chrome/wallpaper_search/combobox_test.ts
+++ b/chrome/test/data/webui/side_panel/customize_chrome/wallpaper_search/combobox_test.ts
@@ -4,42 +4,51 @@
 
 import 'chrome://customize-chrome-side-panel.top-chrome/wallpaper_search/combobox/customize_chrome_combobox.js';
 
-import {CustomizeChromeCombobox, OptionElement} from 'chrome://customize-chrome-side-panel.top-chrome/wallpaper_search/combobox/customize_chrome_combobox.js';
+import {CustomizeChromeCombobox} from 'chrome://customize-chrome-side-panel.top-chrome/wallpaper_search/combobox/customize_chrome_combobox.js';
 import {assertEquals, assertFalse, assertNotEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
-import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
+import {flushTasks, waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js';
 import {eventToPromise, isVisible} from 'chrome://webui-test/test_util.js';
 
 suite('ComboboxTest', () => {
   let combobox: CustomizeChromeCombobox;
 
-  function addGroup(): HTMLElement {
-    const group = document.createElement('div');
-    group.setAttribute('role', 'group');
-    const label = document.createElement('label');
-    label.innerText = 'Group';
-    group.appendChild(label);
-    combobox.appendChild(group);
-    return label;
+  function getGroup(groupIndex: number): HTMLElement {
+    return combobox.shadowRoot!.querySelectorAll('[role=group]')[groupIndex] as
+        HTMLElement;
   }
 
-  function addOption(
-      parent: HTMLElement = combobox, value: string = 'value'): OptionElement {
-    const option = document.createElement('div') as OptionElement;
-    option.setAttribute('role', 'option');
-    option.innerText = 'Option';
-    option.value = value;
-    parent.appendChild(option);
-    return option;
+  function getOptionFromGroup(
+      groupIndex: number, optionIndex: number): HTMLElement {
+    return getGroup(groupIndex)
+               .querySelectorAll('[role=option]')[optionIndex] as HTMLElement;
+  }
+
+  function getOption(optionIndex: number): HTMLElement {
+    return combobox.shadowRoot!.querySelectorAll(
+               '[role=option]')[optionIndex] as HTMLElement;
+  }
+
+  function toggleGroupExpand(groupIndex: number) {
+    getGroup(groupIndex)
+        .querySelector('label')!.dispatchEvent(new Event('click'));
+  }
+
+  function getHighlightedElement() {
+    return combobox.shadowRoot!.querySelector('[highlighted]');
   }
 
   setup(async () => {
     document.body.innerHTML = window.trustedTypes!.emptyHTML;
     combobox = document.createElement('customize-chrome-combobox');
+    combobox.items = [
+      {label: 'Option 1'},
+      {label: 'Option 2'},
+    ];
     document.body.appendChild(combobox);
+    return flushTasks();
   });
 
   test('ShowsAndHides', () => {
-    addOption();
     assertFalse(isVisible(combobox.$.dropdown));
     combobox.$.input.click();
     assertTrue(isVisible(combobox.$.dropdown));
@@ -49,87 +58,107 @@
   });
 
   test('OpensAndClosesDropdownOnKeydown', async () => {
-    const option1 = addOption();
-    const option2 = addOption();
-    await flushTasks();
-    assertFalse(isVisible(combobox.$.dropdown));
-
     function assertDropdownOpensAndHighlightsFirst(
         key: string, expectedHighlight: HTMLElement) {
       combobox.dispatchEvent(new KeyboardEvent('keydown', {key}));
       assertTrue(isVisible(combobox.$.dropdown));
-      assertEquals(expectedHighlight, combobox.querySelector('[highlighted]'));
+      assertEquals(
+          expectedHighlight,
+          combobox.shadowRoot!.querySelector('[highlighted]'));
       // Close the dropdown.
       combobox.dispatchEvent(new KeyboardEvent('keydown', {key: 'Escape'}));
     }
 
-    assertDropdownOpensAndHighlightsFirst('ArrowDown', option1);
-    assertDropdownOpensAndHighlightsFirst('ArrowUp', option2);
-    assertDropdownOpensAndHighlightsFirst('Home', option1);
-    assertDropdownOpensAndHighlightsFirst('End', option2);
-    assertDropdownOpensAndHighlightsFirst('Enter', option1);
-    assertDropdownOpensAndHighlightsFirst('Space', option1);
+    assertDropdownOpensAndHighlightsFirst('ArrowDown', getOption(0));
+    assertDropdownOpensAndHighlightsFirst('ArrowUp', getOption(1));
+    assertDropdownOpensAndHighlightsFirst('Home', getOption(0));
+    assertDropdownOpensAndHighlightsFirst('End', getOption(1));
+    assertDropdownOpensAndHighlightsFirst('Enter', getOption(0));
+    assertDropdownOpensAndHighlightsFirst('Space', getOption(0));
   });
 
   test('HighlightsItemsOnKeydownWhenOpen', async () => {
-    const groupA = addGroup();
-    const optionA1 = addOption(groupA);
-    const optionA2 = addOption(groupA);
-    const groupB = addGroup();
-    const optionB1 = addOption(groupB);
+    combobox.items = [
+      {
+        label: 'Group A',
+        items: [{label: 'Option A1'}, {label: 'OptionA2'}],
+      },
+      {
+        label: 'Group B',
+        items: [{label: 'Option B1'}],
+      },
+    ];
     await flushTasks();
 
+    toggleGroupExpand(0);
+    toggleGroupExpand(1);
+    await flushTasks();
+
+    const groupA = getGroup(0);
+    const optionA1 = getOptionFromGroup(0, 0);
+    const optionA2 = getOptionFromGroup(0, 1);
+    const groupB = getGroup(1);
+    const optionB1 = getOptionFromGroup(1, 0);
+
     // ArrowDown should loop through list.
     combobox.$.input.click();
     combobox.dispatchEvent(new KeyboardEvent('keydown', {key: 'ArrowDown'}));
-    assertEquals(groupA, combobox.querySelector('[highlighted]'));
+    assertEquals(groupA.querySelector('label'), getHighlightedElement());
     combobox.dispatchEvent(new KeyboardEvent('keydown', {key: 'ArrowDown'}));
-    assertEquals(optionA1, combobox.querySelector('[highlighted]'));
+    assertEquals(optionA1, getHighlightedElement());
     combobox.dispatchEvent(new KeyboardEvent('keydown', {key: 'ArrowDown'}));
-    assertEquals(optionA2, combobox.querySelector('[highlighted]'));
+    assertEquals(optionA2, getHighlightedElement());
     combobox.dispatchEvent(new KeyboardEvent('keydown', {key: 'ArrowDown'}));
-    assertEquals(groupB, combobox.querySelector('[highlighted]'));
+    assertEquals(groupB.querySelector('label'), getHighlightedElement());
     combobox.dispatchEvent(new KeyboardEvent('keydown', {key: 'ArrowDown'}));
-    assertEquals(optionB1, combobox.querySelector('[highlighted]'));
+    assertEquals(optionB1, getHighlightedElement());
     combobox.dispatchEvent(new KeyboardEvent('keydown', {key: 'ArrowDown'}));
-    assertEquals(groupA, combobox.querySelector('[highlighted]'));
+    assertEquals(groupA.querySelector('label'), getHighlightedElement());
 
     // ArrowUp goes reverse order.
     combobox.dispatchEvent(new KeyboardEvent('keydown', {key: 'ArrowUp'}));
-    assertEquals(optionB1, combobox.querySelector('[highlighted]'));
+    assertEquals(optionB1, getHighlightedElement());
 
     // Home and End keys work.
     combobox.dispatchEvent(new KeyboardEvent('keydown', {key: 'Home'}));
-    assertEquals(groupA, combobox.querySelector('[highlighted]'));
+    assertEquals(groupA.querySelector('label'), getHighlightedElement());
     combobox.dispatchEvent(new KeyboardEvent('keydown', {key: 'End'}));
-    assertEquals(optionB1, combobox.querySelector('[highlighted]'));
+    assertEquals(optionB1, getHighlightedElement());
 
     // Closes when hitting Escape and resets highlight.
     combobox.dispatchEvent(new KeyboardEvent('keydown', {key: 'Escape'}));
     assertFalse(isVisible(combobox.$.dropdown));
-    assertEquals(null, combobox.querySelector('[highlighted]'));
+    assertEquals(null, getHighlightedElement());
   });
 
   test('HighlightsOnPointerover', async () => {
-    const group = addGroup();
-    const option = addOption(group);
+    combobox.items = [
+      {
+        label: 'Group A',
+        items: [{label: 'Option A1'}],
+      },
+    ];
     await flushTasks();
+    toggleGroupExpand(0);
+    await flushTasks();
+
+    const group = getGroup(0);
+    const option = getOptionFromGroup(0, 0);
 
     // Open the dropdown.
     combobox.$.input.click();
 
-    group.dispatchEvent(
+    group.querySelector('label')!.dispatchEvent(
         new PointerEvent('pointerover', {bubbles: true, composed: true}));
-    assertEquals(group, combobox.querySelector('[highlighted]'));
+    assertEquals(group.querySelector('label'), getHighlightedElement());
     option.dispatchEvent(
         new PointerEvent('pointerover', {bubbles: true, composed: true}));
-    assertEquals(option, combobox.querySelector('[highlighted]'));
+    assertEquals(option, getHighlightedElement());
   });
 
   test('HighlightsOnPointermoveAfterKeyEvent', async () => {
-    const option1 = addOption();
-    const option2 = addOption();
-    await flushTasks();
+    const option1 = getOption(0);
+    const option2 = getOption(1);
 
     // Open the dropdown.
     combobox.$.input.click();
@@ -137,30 +166,37 @@
     // Mouse moves to first option.
     option1.dispatchEvent(
         new PointerEvent('pointerover', {bubbles: true, composed: true}));
-    assertEquals(option1, combobox.querySelector('[highlighted]'));
+    assertEquals(option1, getHighlightedElement());
 
     // Keydown down to highlight second option. Mouse still over first option.
     combobox.dispatchEvent(new KeyboardEvent('keydown', {key: 'ArrowDown'}));
-    assertEquals(option2, combobox.querySelector('[highlighted]'));
+    assertEquals(option2, getHighlightedElement());
 
     // Pointerover event over first option should not highlight first option,
     // since it follows a key event.
     option1.dispatchEvent(new PointerEvent('pointerover'));
-    assertEquals(option2, combobox.querySelector('[highlighted]'));
+    assertEquals(option2, getHighlightedElement());
 
     // Mock moving mouse within the first option again.
     option1.dispatchEvent(
         new PointerEvent('pointermove', {bubbles: true, composed: true}));
-    assertEquals(option1, combobox.querySelector('[highlighted]'));
+    assertEquals(option1, getHighlightedElement());
   });
 
   test('SelectsItem', async () => {
-    const groupA = addGroup();
-    const optionA1 = addOption(groupA);
-    optionA1.innerText = 'I am option 1';
-    const optionA2 = addOption(groupA);
-    optionA2.innerText = 'I am option 2';
+    combobox.items = [
+      {
+        label: 'Group A',
+        items: [{label: 'I am option 1'}, {label: 'I am option 2'}],
+      },
+    ];
     await flushTasks();
+    toggleGroupExpand(0);
+    await flushTasks();
+
+    const groupA = getGroup(0);
+    const optionA1 = getOptionFromGroup(0, 0);
+    const optionA2 = getOptionFromGroup(0, 1);
 
     // Open dropdown, click on first option to select it.
     combobox.$.input.click();
@@ -193,74 +229,41 @@
   });
 
   test('NotifiesValueChange', async () => {
-    const option1 = addOption();
-    option1.value = 'option-1-value';
-    const option2 = addOption();
-    option2.value = 'option-2-value';
+    const option1 = getOption(0);
+    const option2 = getOption(1);
 
     let valueChangeEvent = eventToPromise('value-changed', combobox);
     combobox.$.input.click();
     option1.dispatchEvent(new Event('click', {composed: true, bubbles: true}));
     await valueChangeEvent;
-    assertEquals('option-1-value', combobox.value);
+    assertEquals('Option 1', combobox.value);
     assertTrue(option1.hasAttribute('selected'));
 
     valueChangeEvent = eventToPromise('value-changed', combobox);
     combobox.$.input.click();
     option2.dispatchEvent(new Event('click', {composed: true, bubbles: true}));
-    assertEquals('option-2-value', combobox.value);
+    assertEquals('Option 2', combobox.value);
     assertTrue(option2.hasAttribute('selected'));
   });
 
   test('UpdatesWithBoundValue', async () => {
-    const option1 = addOption();
-    option1.value = 'option-1-value';
-    const option2 = addOption();
-    option2.value = 'option-2-value';
+    const option1 = getOption(0);
+    const option2 = getOption(1);
 
-    combobox.value = 'option-1-value';
+    combobox.value = 'Option 1';
+    await waitAfterNextRender(combobox);
     assertTrue(option1.hasAttribute('selected'));
     assertFalse(option2.hasAttribute('selected'));
 
-    combobox.value = 'option-2-value';
+    combobox.value = 'Option 2';
+    await waitAfterNextRender(combobox);
     assertFalse(option1.hasAttribute('selected'));
     assertTrue(option2.hasAttribute('selected'));
   });
 
-  test('UpdatesWithBoundValueOnDomChange', async () => {
-    const groupA = addGroup();
-    addOption(groupA, 'valueA1');
-    const groupB = addGroup();
-
-    // Set the bound value to an option that does not exist yet.
-    combobox.value = 'valueB1';
-    await flushTasks();
-    assertEquals(0, combobox.querySelectorAll('[selected]').length);
-
-    // Add an option with the selected value.
-    const optionB1 = addOption(groupB, 'valueB1');
-    await flushTasks();
-    assertEquals(1, combobox.querySelectorAll('[selected]').length);
-    assertTrue(optionB1.hasAttribute('selected'));
-
-    // Removing the option should keep the bound value.
-    optionB1.remove();
-    await flushTasks();
-    assertEquals('valueB1', combobox.value);
-    assertEquals(0, combobox.querySelectorAll('[selected]').length);
-
-    // Adding a new option with the same value should select it.
-    const newOptionB1 = addOption(groupB, 'valueB1');
-    await flushTasks();
-    assertEquals(1, combobox.querySelectorAll('[selected]').length);
-    assertTrue(newOptionB1.hasAttribute('selected'));
-  });
-
   test('SetsUniqueIdsAndAriaActiveDescendant', async () => {
-    const option1 = addOption();
-    option1.value = 'option-1-value';
-    const option2 = addOption();
-    option2.value = 'option-2-value';
+    const option1 = getOption(0);
+    const option2 = getOption(1);
     await flushTasks();
 
     assertTrue(option1.id.includes('comboboxItem'));
@@ -276,4 +279,63 @@
     assertEquals(
         option2.id, combobox.$.input.getAttribute('aria-activedescendant'));
   });
+
+  test('ExpandsAndCollapsesCategories', async () => {
+    combobox.items = [
+      {
+        label: 'Group A',
+        items: [{label: 'I am option 1'}, {label: 'I am option 2'}],
+      },
+    ];
+    await flushTasks();
+
+    // No options should be visible yet since group is by default collapsed.
+    assertEquals(
+        0, combobox.shadowRoot!.querySelectorAll('[role=option]').length);
+
+    const groupLabel = getGroup(0).querySelector('label')!;
+    const groupLabelIcon = groupLabel.querySelector('iron-icon')!;
+    assertEquals('cr:expand-more', groupLabelIcon.icon);
+
+    // // Clicking on a group expands the dropdown items below it.
+    toggleGroupExpand(0);
+    await flushTasks();
+    assertEquals(
+        2, combobox.shadowRoot!.querySelectorAll('[role=option]').length);
+    assertEquals('cr:expand-less', groupLabelIcon.icon);
+
+    // // Clicking on the group again hides the dropdown items below it.
+    toggleGroupExpand(0);
+    await flushTasks();
+    assertEquals(
+        0, combobox.shadowRoot!.querySelectorAll('[role=option]').length);
+    assertEquals('cr:expand-more', groupLabelIcon.icon);
+  });
+
+  test('CheckmarksSelectedOption', async () => {
+    combobox.items = [
+      {label: 'Option 1', imagePath: 'image/path1.png'},
+      {label: 'Option 2', imagePath: 'image/path2.png'},
+    ];
+    await flushTasks();
+
+    const optionCheckmarks = combobox.shadowRoot!.querySelectorAll(
+        'customize-chrome-check-mark-wrapper');
+    assertEquals(2, optionCheckmarks.length);
+
+    const option1Checkmark = optionCheckmarks[0]!;
+    const option2Checkmark = optionCheckmarks[1]!;
+    assertFalse(option1Checkmark.checked);
+    assertFalse(option2Checkmark.checked);
+
+    combobox.value = 'Option 1';
+    await flushTasks();
+    assertTrue(option1Checkmark.checked);
+    assertFalse(option2Checkmark.checked);
+
+    combobox.value = 'Option 2';
+    await flushTasks();
+    assertFalse(option1Checkmark.checked);
+    assertTrue(option2Checkmark.checked);
+  });
 });
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_test.ts b/chrome/test/data/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_test.ts
index 8db45b7..d9318a4 100644
--- a/chrome/test/data/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_test.ts
+++ b/chrome/test/data/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_test.ts
@@ -9,6 +9,7 @@
 import {CustomizeChromePageRemote} from 'chrome://customize-chrome-side-panel.top-chrome/customize_chrome.mojom-webui.js';
 import {CustomizeChromeApiProxy} from 'chrome://customize-chrome-side-panel.top-chrome/customize_chrome_api_proxy.js';
 import {Descriptors, UserFeedback, WallpaperSearchClientCallbackRouter, WallpaperSearchClientRemote, WallpaperSearchHandlerInterface, WallpaperSearchHandlerRemote, WallpaperSearchStatus} from 'chrome://customize-chrome-side-panel.top-chrome/wallpaper_search.mojom-webui.js';
+import {CustomizeChromeCombobox} from 'chrome://customize-chrome-side-panel.top-chrome/wallpaper_search/combobox/customize_chrome_combobox.js';
 import {DESCRIPTOR_D_VALUE, WallpaperSearchElement} from 'chrome://customize-chrome-side-panel.top-chrome/wallpaper_search/wallpaper_search.js';
 import {WallpaperSearchProxy} from 'chrome://customize-chrome-side-panel.top-chrome/wallpaper_search/wallpaper_search_proxy.js';
 import {WindowProxy} from 'chrome://customize-chrome-side-panel.top-chrome/window_proxy.js';
@@ -115,18 +116,18 @@
       assertEquals(
           1,
           wallpaperSearchElement.shadowRoot!
-              .querySelectorAll('#descriptorComboboxA .category-item')
-              .length);
+              .querySelector<CustomizeChromeCombobox>(
+                  '#descriptorComboboxA')!.items.length);
       assertEquals(
           1,
           wallpaperSearchElement.shadowRoot!
-              .querySelectorAll('#descriptorComboboxB .dropdown-item')
-              .length);
+              .querySelector<CustomizeChromeCombobox>(
+                  '#descriptorComboboxB')!.items.length);
       assertEquals(
           3,
           wallpaperSearchElement.shadowRoot!
-              .querySelectorAll('#descriptorComboboxC .dropdown-item')
-              .length);
+              .querySelector<CustomizeChromeCombobox>(
+                  '#descriptorComboboxC')!.items.length);
       assertEquals(
           6,
           wallpaperSearchElement.shadowRoot!
@@ -134,76 +135,6 @@
               .length);
     });
 
-    test('expands and collapses categories', async () => {
-      createWallpaperSearchElementWithDescriptors();
-      await flushTasks();
-
-      // No dropdown items by default since all categories are collapsed.
-      assertEquals(
-          0,
-          wallpaperSearchElement.shadowRoot!
-              .querySelectorAll('#descriptorComboboxA .dropdown-item')
-              .length);
-
-      const categoryLabel =
-          wallpaperSearchElement.shadowRoot!.querySelector<HTMLElement>(
-              '#descriptorComboboxA .category-item')!;
-      const categoryLabelIcon = categoryLabel.querySelector('iron-icon')!;
-      assertEquals('cr:expand-more', categoryLabelIcon.icon);
-
-      // Clicking on a category expands the dropdown items below it.
-      categoryLabel.click();
-      await flushTasks();
-      assertEquals(
-          2,
-          wallpaperSearchElement.shadowRoot!
-              .querySelectorAll('#descriptorComboboxA .dropdown-item')
-              .length);
-      assertEquals('cr:expand-less', categoryLabelIcon.icon);
-
-      // Clicking on the category again hides the dropdown items below it.
-      categoryLabel.click();
-      await flushTasks();
-      assertEquals(
-          0,
-          wallpaperSearchElement.shadowRoot!
-              .querySelectorAll('#descriptorComboboxA .dropdown-item')
-              .length);
-      assertEquals('cr:expand-more', categoryLabelIcon.icon);
-    });
-
-    test('check marks selected descriptorComboboxB option', async () => {
-      createWallpaperSearchElement({
-        descriptorA: [],
-        descriptorB: [
-          {label: 'one', imagePath: 'one.png'},
-          {label: 'two', imagePath: 'two.png'},
-        ],
-        descriptorC: [],
-      });
-      await flushTasks();
-
-      const optionCheckmarks =
-          wallpaperSearchElement.$.descriptorComboboxB.querySelectorAll(
-              'customize-chrome-check-mark-wrapper');
-      assertEquals(2, optionCheckmarks.length);
-
-      const option1Checkmark = optionCheckmarks[0]!;
-      const option2Checkmark = optionCheckmarks[1]!;
-      assertFalse(option1Checkmark.checked);
-      assertFalse(option2Checkmark.checked);
-
-      wallpaperSearchElement.$.descriptorComboboxB.value = 'one';
-      await flushTasks();
-      assertTrue(option1Checkmark.checked);
-      assertFalse(option2Checkmark.checked);
-
-      wallpaperSearchElement.$.descriptorComboboxB.value = 'two';
-      await flushTasks();
-      assertFalse(option1Checkmark.checked);
-      assertTrue(option2Checkmark.checked);
-    });
-
     test('check marks one item in descriptorMenuD at a time', async () => {
       createWallpaperSearchElementWithDescriptors();
       await flushTasks();
@@ -263,19 +194,12 @@
       });
       await flushTasks();
 
-      $$<HTMLElement>(
-          wallpaperSearchElement,
-          '#descriptorComboboxA .category-item')!.click();
-      await flushTasks();
-      $$<HTMLElement>(
-          wallpaperSearchElement,
-          '#descriptorComboboxA .dropdown-item')!.click();
-      $$<HTMLElement>(
-          wallpaperSearchElement,
-          '#descriptorComboboxB .dropdown-item')!.click();
-      $$<HTMLElement>(
-          wallpaperSearchElement,
-          '#descriptorComboboxC .dropdown-item')!.click();
+      $$<CustomizeChromeCombobox>(
+          wallpaperSearchElement, '#descriptorComboboxA')!.value = 'bar';
+      $$<CustomizeChromeCombobox>(
+          wallpaperSearchElement, '#descriptorComboboxB')!.value = 'foo';
+      $$<CustomizeChromeCombobox>(
+          wallpaperSearchElement, '#descriptorComboboxC')!.value = 'baz';
       $$<HTMLElement>(
           wallpaperSearchElement, '#descriptorMenuD button')!.click();
       wallpaperSearchElement.$.submitButton.click();
@@ -323,14 +247,6 @@
 
           wallpaperSearchElement.$.submitButton.click();
           await flushTasks();
-
-          // Category is expanded to reveal dropdown items.
-          assertEquals(
-              2,
-              wallpaperSearchElement.shadowRoot!
-                  .querySelectorAll('#descriptorComboboxA .dropdown-item')
-                  .length);
-
           assertEquals(1, handler.getCallCount('getWallpaperSearchResults'));
           assertNotEquals(
               undefined, wallpaperSearchElement.$.descriptorComboboxA.value);
@@ -348,13 +264,9 @@
       });
       await flushTasks();
 
-      $$<HTMLElement>(
-          wallpaperSearchElement,
-          '#descriptorComboboxA .category-item')!.click();
+      $$<CustomizeChromeCombobox>(
+          wallpaperSearchElement, '#descriptorComboboxA')!.value = 'bar';
       await flushTasks();
-      $$<HTMLElement>(
-          wallpaperSearchElement,
-          '#descriptorComboboxA .dropdown-item')!.click();
       wallpaperSearchElement.$.submitButton.click();
 
       assertEquals(1, handler.getCallCount('getWallpaperSearchResults'));
@@ -590,13 +502,9 @@
       await flushTasks();
 
       // Select only descriptor A.
-      $$<HTMLElement>(
-          wallpaperSearchElement,
-          '#descriptorComboboxA .category-item')!.click();
+      $$<CustomizeChromeCombobox>(
+          wallpaperSearchElement, '#descriptorComboboxA')!.value = 'Label A1';
       await flushTasks();
-      $$<HTMLElement>(
-          wallpaperSearchElement,
-          '#descriptorComboboxA .dropdown-item')!.click();
       wallpaperSearchElement.$.submitButton.click();
       await waitAfterNextRender(wallpaperSearchElement);
 
@@ -609,18 +517,18 @@
       assertEquals('Image 2 of Label A1', getAriaLabelOfTile(1));
 
       // Select descriptor B.
-      $$<HTMLElement>(
-          wallpaperSearchElement,
-          '#descriptorComboboxB .dropdown-item')!.click();
+      $$<CustomizeChromeCombobox>(
+          wallpaperSearchElement, '#descriptorComboboxB')!.value = 'Label B';
+      await flushTasks();
       wallpaperSearchElement.$.submitButton.click();
       await waitAfterNextRender(wallpaperSearchElement);
       assertEquals('Image 1 of Label A1, Label B', getAriaLabelOfTile(0));
       assertEquals('Image 2 of Label A1, Label B', getAriaLabelOfTile(1));
 
       // Select descriptor C.
-      $$<HTMLElement>(
-          wallpaperSearchElement,
-          '#descriptorComboboxC .dropdown-item')!.click();
+      $$<CustomizeChromeCombobox>(
+          wallpaperSearchElement, '#descriptorComboboxC')!.value = 'Label C';
+      await flushTasks();
       wallpaperSearchElement.$.submitButton.click();
       await waitAfterNextRender(wallpaperSearchElement);
       assertEquals(
@@ -636,16 +544,11 @@
         descriptorC: ['Label C'],
       });
       await flushTasks();
-      $$<HTMLElement>(
-          wallpaperSearchElement,
-          '#descriptorComboboxA .category-item')!.click();
+      $$<CustomizeChromeCombobox>(
+          wallpaperSearchElement, '#descriptorComboboxA')!.value = 'Label A1';
+      $$<CustomizeChromeCombobox>(
+          wallpaperSearchElement, '#descriptorComboboxC')!.value = 'Label C';
       await flushTasks();
-      $$<HTMLElement>(
-          wallpaperSearchElement,
-          '#descriptorComboboxA .dropdown-item')!.click();
-      $$<HTMLElement>(
-          wallpaperSearchElement,
-          '#descriptorComboboxC .dropdown-item')!.click();
       wallpaperSearchElement.$.submitButton.click();
       await waitAfterNextRender(wallpaperSearchElement);
       assertEquals('Image 1 of Label A1, Label C', getAriaLabelOfTile(0));
@@ -1199,13 +1102,9 @@
       createWallpaperSearchElementWithDescriptors();
       await flushTasks();
 
-      $$<HTMLElement>(
-          wallpaperSearchElement,
-          '#descriptorComboboxA .category-item')!.click();
+      $$<CustomizeChromeCombobox>(
+          wallpaperSearchElement, '#descriptorComboboxA')!.value = 'bar';
       await flushTasks();
-      $$<HTMLElement>(
-          wallpaperSearchElement,
-          '#descriptorComboboxA .dropdown-item')!.click();
 
       assertEquals(
           1, metrics.count('NewTabPage.CustomizeChromeSidePanelAction'));
@@ -1221,9 +1120,9 @@
       createWallpaperSearchElementWithDescriptors();
       await flushTasks();
 
-      $$<HTMLElement>(
-          wallpaperSearchElement,
-          '#descriptorComboboxB .dropdown-item')!.click();
+      $$<CustomizeChromeCombobox>(
+          wallpaperSearchElement, '#descriptorComboboxB')!.value = 'foo';
+      await flushTasks();
 
       assertEquals(
           1, metrics.count('NewTabPage.CustomizeChromeSidePanelAction'));
@@ -1238,9 +1137,9 @@
       createWallpaperSearchElementWithDescriptors();
       await flushTasks();
 
-      $$<HTMLElement>(
-          wallpaperSearchElement,
-          '#descriptorComboboxC .dropdown-item')!.click();
+      $$<CustomizeChromeCombobox>(
+          wallpaperSearchElement, '#descriptorComboboxC')!.value = 'foo';
+      await flushTasks();
 
       assertEquals(
           1, metrics.count('NewTabPage.CustomizeChromeSidePanelAction'));
diff --git a/chrome/test/data/webui/tab_search/tab_organization_page_test.ts b/chrome/test/data/webui/tab_search/tab_organization_page_test.ts
index ec5f1621..5eb0551 100644
--- a/chrome/test/data/webui/tab_search/tab_organization_page_test.ts
+++ b/chrome/test/data/webui/tab_search/tab_organization_page_test.ts
@@ -103,10 +103,6 @@
     const notStarted = tabOrganizationPage.shadowRoot!.querySelector(
         'tab-organization-not-started');
     assertTrue(!!notStarted);
-    const animations = notStarted.getAnimations();
-    assertEquals(2, animations.length);
-    animations[0]!.finish();
-    animations[1]!.finish();
     assertTrue(isVisible(notStarted));
 
     const organizeTabsButton =
@@ -301,10 +297,6 @@
     const notStarted = tabOrganizationPage.shadowRoot!.querySelector(
         'tab-organization-not-started');
     assertTrue(!!notStarted);
-    const animations = notStarted.getAnimations();
-    assertEquals(2, animations.length);
-    animations[0]!.finish();
-    animations[1]!.finish();
     assertTrue(isVisible(notStarted));
 
     const actionButton = notStarted.shadowRoot!.querySelector('cr-button');
@@ -382,10 +374,6 @@
     const notStarted = tabOrganizationPage.shadowRoot!.querySelector(
         'tab-organization-not-started');
     assertTrue(!!notStarted);
-    const animations = notStarted.getAnimations();
-    assertEquals(2, animations.length);
-    animations[0]!.finish();
-    animations[1]!.finish();
     assertTrue(isVisible(notStarted));
 
     const accountRowSynced =
diff --git a/chrome/test/supervised_user/family_live_test.cc b/chrome/test/supervised_user/family_live_test.cc
index 9224a7ef..9ae7840 100644
--- a/chrome/test/supervised_user/family_live_test.cc
+++ b/chrome/test/supervised_user/family_live_test.cc
@@ -29,10 +29,10 @@
 namespace {
 
 // List of accounts specified in
-// chrome/browser/internal/resources/signin/test_accounts.json
+// chrome/browser/internal/resources/signin/test_accounts.json.
 static constexpr std::string_view kHeadOfHouseholdAccountId{
-    "FAMILY_HEAD_OF_HOUSEHOLD"};
-static constexpr std::string_view kChildAccountId{"FAMILY_CHILD_1"};
+    "HEAD_OF_HOUSEHOLD"};
+static constexpr std::string_view kChildAccountId{"CHILD_1"};
 
 Profile& CreateNewProfile() {
   ProfileManager* profile_manager = g_browser_process->profile_manager();
@@ -41,12 +41,21 @@
   return profiles::testing::CreateProfileSync(profile_manager, profile_path);
 }
 
+std::string GetFamilyMemberIdentifier(FamilyIdentifier family_identifier,
+                                      std::string_view member_identifier) {
+  return family_identifier.value() + "_" + std::string(member_identifier);
+}
+
 }  // namespace
 
 FamilyLiveTest::FamilyLiveTest() = default;
+FamilyLiveTest::FamilyLiveTest(FamilyIdentifier family_identifier)
+    : family_identifier_(family_identifier) {}
 FamilyLiveTest::FamilyLiveTest(
+    FamilyIdentifier famiy_identifier,
     const std::vector<std::string>& extra_enabled_hosts)
-    : extra_enabled_hosts_(extra_enabled_hosts) {}
+    : family_identifier_(famiy_identifier),
+      extra_enabled_hosts_(extra_enabled_hosts) {}
 FamilyLiveTest::~FamilyLiveTest() = default;
 
 /* static */ void FamilyLiveTest::TurnOnSyncFor(FamilyMember& member) {
@@ -67,8 +76,10 @@
 void FamilyLiveTest::SetUpOnMainThread() {
   signin::test::LiveTest::SetUpOnMainThread();
 
-  child_ = MakeSignedInBrowser(kChildAccountId);
-  head_of_household_ = MakeSignedInBrowser(kHeadOfHouseholdAccountId);
+  child_ = MakeSignedInBrowser(
+      GetFamilyMemberIdentifier(family_identifier_, kChildAccountId));
+  head_of_household_ = MakeSignedInBrowser(
+      GetFamilyMemberIdentifier(family_identifier_, kHeadOfHouseholdAccountId));
 }
 
 void FamilyLiveTest::SetUpInProcessBrowserTestFixture() {
@@ -86,8 +97,17 @@
   return account;
 }
 
+bool FamilyLiveTest::TestAccountExists(std::string_view account_name) const {
+  signin::test::TestAccount account;
+  return GetTestAccountsUtil()->GetAccount(std::string(account_name), account);
+}
+
 std::unique_ptr<FamilyMember> FamilyLiveTest::MakeSignedInBrowser(
     std::string_view account_name) {
+  if (!TestAccountExists(std::string(account_name))) {
+    return nullptr;
+  }
+
   // Managed externally to the test fixture.
   Profile& profile = CreateNewProfile();
   Browser* browser = CreateBrowser(&profile);
diff --git a/chrome/test/supervised_user/family_live_test.h b/chrome/test/supervised_user/family_live_test.h
index 6335a510..0b8c5eec5 100644
--- a/chrome/test/supervised_user/family_live_test.h
+++ b/chrome/test/supervised_user/family_live_test.h
@@ -10,6 +10,7 @@
 #include <string_view>
 
 #include "base/test/scoped_feature_list.h"
+#include "base/types/strong_alias.h"
 #include "chrome/browser/signin/e2e_tests/live_test.h"
 #include "chrome/browser/signin/e2e_tests/signin_util.h"
 #include "chrome/browser/signin/e2e_tests/test_accounts_util.h"
@@ -21,6 +22,9 @@
 
 namespace supervised_user {
 
+using FamilyIdentifier =
+    base::StrongAlias<class FamilyIdentifierTag, std::string>;
+
 // A LiveTest which assumes a specific structure of provided test accounts,
 // which are forming a family:
 // * head of household,
@@ -29,7 +33,12 @@
  public:
   FamilyLiveTest();
   // Navigation will be allowed to extra hosts.
-  explicit FamilyLiveTest(const std::vector<std::string>& extra_enabled_hosts);
+  explicit FamilyLiveTest(FamilyIdentifier family_identifier);
+  // The provided family identifier will be used to select the test accounts.
+  // Navigation will be allowed to extra hosts.
+  FamilyLiveTest(FamilyIdentifier family_identifier,
+                 const std::vector<std::string>& extra_enabled_hosts);
+
   ~FamilyLiveTest() override;
 
   // Turns on sync and closes auxiliary tabs.
@@ -44,8 +53,16 @@
   // explicitly added to `extra_enabled_hosts`.
   GURL GetRoutedUrl(std::string_view url_spec) const;
 
-  FamilyMember& head_of_household() { return *head_of_household_; }
-  FamilyMember& child() { return *child_; }
+  FamilyMember& head_of_household() {
+    CHECK(head_of_household_) << "No head of household found in family: " +
+                                     std::string(family_identifier_->data());
+    return *head_of_household_;
+  }
+  FamilyMember& child() {
+    CHECK(child_) << "No child found in family: " +
+                         std::string(family_identifier_->data());
+    return *child_;
+  }
 
  private:
   base::test::ScopedFeatureList features{
@@ -53,12 +70,15 @@
 
   // Extracts requested account, which must exist.
   signin::test::TestAccount GetTestAccount(std::string_view account_name) const;
+  // Checks if test account exists.
+  bool TestAccountExists(std::string_view account_name) const;
 
   // Creates a new browser signed in to the specified account, which must
   // exist.
   std::unique_ptr<FamilyMember> MakeSignedInBrowser(
       std::string_view account_name);
 
+  FamilyIdentifier family_identifier_;
   std::unique_ptr<FamilyMember> head_of_household_;
   std::unique_ptr<FamilyMember> child_;
 
diff --git a/chromeos/ash/components/fwupd/firmware_update_manager.cc b/chromeos/ash/components/fwupd/firmware_update_manager.cc
index 2598a56..7424e1f 100644
--- a/chromeos/ash/components/fwupd/firmware_update_manager.cc
+++ b/chromeos/ash/components/fwupd/firmware_update_manager.cc
@@ -209,10 +209,11 @@
 }
 
 int GetResponseCode(network::SimpleURLLoader* simple_loader) {
-  if (simple_loader->ResponseInfo() && simple_loader->ResponseInfo()->headers)
+  if (simple_loader->ResponseInfo() && simple_loader->ResponseInfo()->headers) {
     return simple_loader->ResponseInfo()->headers->response_code();
-  else
+  } else {
     return -1;
+  }
 }
 
 // TODO(michaelcheco): Determine if more granular states are needed.
diff --git a/chromeos/ash/components/fwupd/firmware_update_manager_unittest.cc b/chromeos/ash/components/fwupd/firmware_update_manager_unittest.cc
index e55ac3e6..f84436ce 100644
--- a/chromeos/ash/components/fwupd/firmware_update_manager_unittest.cc
+++ b/chromeos/ash/components/fwupd/firmware_update_manager_unittest.cc
@@ -565,8 +565,9 @@
     update_provider_remote_->PrepareForUpdate(
         device_id, pending_remote_future.GetCallback());
     auto pending_remote = pending_remote_future.Take();
-    if (!pending_remote.is_valid())
+    if (!pending_remote.is_valid()) {
       return false;
+    }
 
     install_controller_remote_.Bind(std::move(pending_remote));
     base::RunLoop().RunUntilIdle();
diff --git a/chromeos/ash/components/fwupd/histogram_util.cc b/chromeos/ash/components/fwupd/histogram_util.cc
index 614c739..cbf41f38 100644
--- a/chromeos/ash/components/fwupd/histogram_util.cc
+++ b/chromeos/ash/components/fwupd/histogram_util.cc
@@ -13,9 +13,8 @@
 const char kHistogramName[] = "ChromeOS.FirmwareUpdateUi.";
 
 }  // namespace
-namespace ash {
-namespace firmware_update {
-namespace metrics {
+namespace ash::firmware_update::metrics {
+
 void EmitDeviceCount(int num_devices, bool is_startup) {
   base::UmaHistogramCounts100(
       GetSourceStr(is_startup) + std::string(".DeviceCount"), num_devices);
@@ -40,6 +39,5 @@
   return std::string(kHistogramName) +
          std::string(is_startup ? "OnStartup" : "OnRefresh");
 }
-}  // namespace metrics
-}  // namespace firmware_update
-}  // namespace ash
+
+}  // namespace ash::firmware_update::metrics
diff --git a/chromeos/ash/components/fwupd/histogram_util.h b/chromeos/ash/components/fwupd/histogram_util.h
index ca4ae20..22003c7 100644
--- a/chromeos/ash/components/fwupd/histogram_util.h
+++ b/chromeos/ash/components/fwupd/histogram_util.h
@@ -8,9 +8,7 @@
 #include <cstdint>
 #include <string>
 
-namespace ash {
-namespace firmware_update {
-namespace metrics {
+namespace ash::firmware_update::metrics {
 
 // The enums below are used in histograms, do not remove/renumber entries. If
 // you're adding to any of these enums, update the corresponding enum listing in
@@ -35,8 +33,6 @@
 
 std::string GetSourceStr(bool is_startup);
 
-}  // namespace metrics
-}  // namespace firmware_update
-}  // namespace ash
+}  // namespace ash::firmware_update::metrics
 
 #endif  // CHROMEOS_ASH_COMPONENTS_FWUPD_HISTOGRAM_UTIL_H_
diff --git a/clank b/clank
index 68277d9..a2fed0c 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit 68277d9bc7d17ef27563d83fcc443e33fbeec22f
+Subproject commit a2fed0cd29a5673211c8327dfd847830ebcbcb24
diff --git a/components/android_autofill/browser/autofill_provider_android_unittest.cc b/components/android_autofill/browser/autofill_provider_android_unittest.cc
index 29760d1..1270f63 100644
--- a/components/android_autofill/browser/autofill_provider_android_unittest.cc
+++ b/components/android_autofill/browser/autofill_provider_android_unittest.cc
@@ -942,11 +942,6 @@
     sub_frame_ = content::RenderFrameHostTester::For(main_frame())
                      ->AppendChild(std::string("child"));
     sub_frame_ = NavigateAndCommitFrame(sub_frame_, GURL("https://bar.com"));
-    // Make sure the driver (and the manager) is created as there is an early
-    // return in `ContentAutofillDriverFactory::DidFinishNavigation` before
-    // `DriverForFrame()` call.
-    ContentAutofillDriverFactory::FromWebContents(web_contents())
-        ->DriverForFrame(sub_frame_);
   }
 
   void TearDown() override {
@@ -1004,7 +999,7 @@
 // *sub frame* hides the popup.
 TEST_F(AutofillProviderAndroidTestHidingLogic, HideInSubFrameOnDestruction) {
   AskForValuesToFill(sub_frame_);
-  EXPECT_CALL(provider_bridge(), HideDatalistPopup).Times(AtLeast(1));
+  EXPECT_CALL(provider_bridge(), Reset);
   NavigateAndCommitFrame(sub_frame_, GURL("https://bar.com/"));
   // Verify and clear before TearDown() closes the popup.
   Mock::VerifyAndClearExpectations(&provider_bridge());
@@ -1047,7 +1042,7 @@
        FollowAskForValuesInDifferentFrames) {
   AskForValuesToFill(main_frame());
   AskForValuesToFill(sub_frame_);
-  EXPECT_CALL(provider_bridge(), HideDatalistPopup).Times(AtLeast(1));
+  EXPECT_CALL(provider_bridge(), Reset);
   NavigateAndCommitFrame(sub_frame_, GURL("https://bar.com/"));
 }
 
diff --git a/components/autofill/content/browser/content_autofill_driver_factory.cc b/components/autofill/content/browser/content_autofill_driver_factory.cc
index 71c307c..3812d73 100644
--- a/components/autofill/content/browser/content_autofill_driver_factory.cc
+++ b/components/autofill/content/browser/content_autofill_driver_factory.cc
@@ -193,13 +193,6 @@
   if (!navigation_handle->HasCommitted()) {
     return;
   }
-
-  // TODO(crbug.com/1492636): Remove after a few days of experimentation.
-  if (!navigation_handle->IsInMainFrame() &&
-      !navigation_handle->HasSubframeNavigationEntryCommitted()) {
-    return;
-  }
-
   auto* driver = DriverForFrame(navigation_handle->GetRenderFrameHost());
   if (!driver) {
     return;
diff --git a/components/autofill/content/browser/content_autofill_driver_unittest.cc b/components/autofill/content/browser/content_autofill_driver_unittest.cc
index 957d8afd..2357f10 100644
--- a/components/autofill/content/browser/content_autofill_driver_unittest.cc
+++ b/components/autofill/content/browser/content_autofill_driver_unittest.cc
@@ -509,18 +509,10 @@
 
  private:
   content::RenderFrameHost* CreateChild(std::string_view name) {
-    content::RenderFrameHost* rfh =
-        content::NavigationSimulator::NavigateAndCommitFromDocument(
-            GURL(base::StrCat({"https://foo.com/", name})),
-            content::RenderFrameHostTester::For(main_rfh())
-                ->AppendChild(std::string(name)));
-    // Make sure the driver (and the manager) is created as there is an early
-    // return in `ContentAutofillDriverFactory::DidFinishNavigation` before
-    // `DriverForFrame()` call.
-    // In non-test setup this method is called during mojom bindings, see
-    // `ContentAutofillDriverFactory::BindAutofillDriver`.
-    factory().DriverForFrame(rfh);
-    return rfh;
+    return content::NavigationSimulator::NavigateAndCommitFromDocument(
+        GURL(base::StrCat({"https://foo.com/", name})),
+        content::RenderFrameHostTester::For(main_rfh())
+            ->AppendChild(std::string(name)));
   }
 
   FormData SeeFormWithField(content::RenderFrameHost* source_rfh,
diff --git a/components/autofill/core/browser/autofill_data_util.cc b/components/autofill/core/browser/autofill_data_util.cc
index 078b513..5d429be 100644
--- a/components/autofill/core/browser/autofill_data_util.cc
+++ b/components/autofill/core/browser/autofill_data_util.cc
@@ -20,7 +20,7 @@
 #include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/browser/form_structure.h"
 #include "components/autofill/core/browser/geo/autofill_country.h"
-#include "components/autofill/core/browser/webdata/autofill_table.h"
+#include "components/autofill/core/browser/webdata/autofill_table_utils.h"
 #include "components/autofill/core/common/autofill_payments_features.h"
 #include "components/grit/components_scaled_resources.h"
 #include "components/strings/grit/components_strings.h"
@@ -361,8 +361,7 @@
 
 std::string TruncateUTF8(const std::string& data) {
   std::string trimmed_value;
-  base::TruncateUTF8ToByteSize(data, AutofillTable::kMaxDataLength,
-                               &trimmed_value);
+  base::TruncateUTF8ToByteSize(data, kMaxDataLengthForDatabase, &trimmed_value);
   return trimmed_value;
 }
 
diff --git a/components/autofill/core/browser/autofill_external_delegate.cc b/components/autofill/core/browser/autofill_external_delegate.cc
index ebb93a4..cf529ef 100644
--- a/components/autofill/core/browser/autofill_external_delegate.cc
+++ b/components/autofill/core/browser/autofill_external_delegate.cc
@@ -182,7 +182,6 @@
       // suggestions related to standalone CVC fields.
     case PopupItemId::kVirtualCreditCardEntry:
     case PopupItemId::kAddressEntryNotSelectable:
-    case PopupItemId::kPaymentsEntryNotSelectable:
       return true;
     case PopupItemId::kAccountStoragePasswordEntry:
     case PopupItemId::kAccountStorageUsernameEntry:
@@ -394,6 +393,10 @@
 
 void AutofillExternalDelegate::DidSelectSuggestion(
     const Suggestion& suggestion) {
+  if (!suggestion.is_selectable) {
+    // TODO(crbug.com/1493361): Handle this in the popup controller.
+    return;
+  }
   ClearPreviewedForm();
 
   const Suggestion::BackendId backend_id =
@@ -468,7 +471,6 @@
                TriggerSourceFromSuggestionTriggerSource(trigger_source_)});
       break;
     case PopupItemId::kAddressEntryNotSelectable:
-    case PopupItemId::kPaymentsEntryNotSelectable:
       return;
     case PopupItemId::kEditAddressProfile:
     case PopupItemId::kDeleteAddressProfile:
@@ -504,6 +506,10 @@
 void AutofillExternalDelegate::DidAcceptSuggestion(
     const Suggestion& suggestion,
     const SuggestionPosition& position) {
+  if (!suggestion.is_selectable) {
+    // TODO(crbug.com/1493361): Handle this in the popup controller.
+    return;
+  }
   switch (suggestion.popup_item_id) {
     case PopupItemId::kAutofillOptions:
       // User selected 'Autofill Options'.
@@ -683,7 +689,6 @@
       // If the selected element is a warning we don't want to do anything.
       break;
     case PopupItemId::kAddressEntryNotSelectable:
-    case PopupItemId::kPaymentsEntryNotSelectable:
       return;
     case PopupItemId::kAddressEntry:
       autofill_metrics::LogAutofillSuggestionAcceptedIndex(
@@ -783,7 +788,6 @@
     case PopupItemId::kCreditCardFieldByFieldFilling:
     case PopupItemId::kCreditCardEntry:
     case PopupItemId::kAddressEntryNotSelectable:
-    case PopupItemId::kPaymentsEntryNotSelectable:
       return manager_->RemoveAutofillProfileOrCreditCard(backend_id);
     case PopupItemId::kAutocompleteEntry:
       manager_->RemoveCurrentSingleFieldSuggestion(query_field_.name, value,
diff --git a/components/autofill/core/browser/autofill_external_delegate_unittest.cc b/components/autofill/core/browser/autofill_external_delegate_unittest.cc
index 15597900..991f2c5 100644
--- a/components/autofill/core/browser/autofill_external_delegate_unittest.cc
+++ b/components/autofill/core/browser/autofill_external_delegate_unittest.cc
@@ -2118,7 +2118,6 @@
     PopupItemId::kCreditCardFieldByFieldFilling,
     PopupItemId::kCreditCardEntry,
     PopupItemId::kAddressEntryNotSelectable,
-    PopupItemId::kPaymentsEntryNotSelectable,
     PopupItemId::kAutocompleteEntry,
     PopupItemId::kPasswordEntry,
 };
diff --git a/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc b/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc
index 5f27a77..cf7010a7 100644
--- a/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc
+++ b/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc
@@ -11,7 +11,7 @@
 #include "components/autofill/core/browser/data_model/autofill_structured_address_component.h"
 #include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/browser/test_autofill_clock.h"
-#include "components/autofill/core/browser/webdata/autofill_table.h"
+#include "components/autofill/core/browser/webdata/autofill_table_utils.h"
 #include "components/autofill/core/common/autofill_constants.h"
 #include "components/autofill/core/common/autofill_features.h"
 #include "components/sync/protocol/autofill_specifics.pb.h"
@@ -697,8 +697,8 @@
 // Test that long fields get trimmed.
 TEST_F(AutofillProfileSyncUtilTest,
        CreateEntityDataFromAutofillProfile_Trimmed) {
-  std::string kNameLong(AutofillTable::kMaxDataLength + 1, 'a');
-  std::string kNameTrimmed(AutofillTable::kMaxDataLength, 'a');
+  std::string kNameLong(kMaxDataLengthForDatabase + 1, 'a');
+  std::string kNameTrimmed(kMaxDataLengthForDatabase, 'a');
 
   AutofillProfile profile(kGuid, AutofillProfile::Source::kLocalOrSyncable,
                           i18n_model_definition::kLegacyHierarchyCountryCode);
@@ -720,7 +720,7 @@
   std::string kNameLong("aä");
   std::string kNameTrimmed("a");
 
-  for (unsigned int i = 0; i < AutofillTable::kMaxDataLength / 2 - 1; ++i) {
+  for (unsigned int i = 0; i < kMaxDataLengthForDatabase / 2 - 1; ++i) {
     kNameLong += "ä";
     kNameTrimmed += "ä";
   }
diff --git a/components/autofill/core/browser/autofill_suggestion_generator.cc b/components/autofill/core/browser/autofill_suggestion_generator.cc
index 97e36a5c..69b721e6 100644
--- a/components/autofill/core/browser/autofill_suggestion_generator.cc
+++ b/components/autofill/core/browser/autofill_suggestion_generator.cc
@@ -590,7 +590,7 @@
 // This function is called only for first-level popup.
 PopupItemId GetProfileSuggestionPopupItemId(
     std::optional<FieldTypeSet> last_targeted_fields,
-    ServerFieldType trigger_field_type) {
+    FieldType trigger_field_type) {
   if (!base::FeatureList::IsEnabled(
           features::kAutofillGranularFillingAvailable)) {
     return PopupItemId::kAddressEntry;
@@ -996,48 +996,47 @@
 }
 
 // Returns whether the `suggestion_canon` is a valid match given
-// `field_contents_canon`.
-bool IsValidSuggestionForFieldContents(std::u16string suggestion_canon,
-                                       std::u16string field_contents_canon,
-                                       FieldType trigger_field_type,
-                                       bool is_masked_server_card,
-                                       bool field_is_autofilled) {
+// `field_contents_canon`. To be used for address suggestions
+bool IsValidAddressSuggestionForFieldContents(
+    std::u16string suggestion_canon,
+    std::u16string field_contents_canon,
+    FieldType trigger_field_type) {
   // Phones should do a substring match because they can be trimmed to remove
   // the first parts (e.g. country code or prefix).
   if (GroupTypeOfFieldType(trigger_field_type) == FieldTypeGroup::kPhone &&
       suggestion_canon.find(field_contents_canon) != std::u16string::npos) {
     return true;
   }
+  return suggestion_canon.starts_with(field_contents_canon);
+}
 
+// Returns whether the `suggestion_canon` is a valid match given
+// `field_contents_canon`. To be used for payments suggestions.
+bool IsValidPaymentsSuggestionForFieldContents(
+    std::u16string suggestion_canon,
+    std::u16string field_contents_canon,
+    FieldType trigger_field_type,
+    bool is_masked_server_card,
+    bool field_is_autofilled) {
+  if (trigger_field_type != CREDIT_CARD_NUMBER) {
+    return suggestion_canon.starts_with(field_contents_canon);
+  }
   // For card number fields, suggest the card if:
   // - the number matches any part of the card, or
   // - it's a masked card and there are 6 or fewer typed so far.
   // - it's a masked card, field is autofilled, and the last 4 digits in the
   // field match the last 4 digits of the card.
-  if (trigger_field_type == CREDIT_CARD_NUMBER) {
-    if (suggestion_canon.find(field_contents_canon) != std::u16string::npos) {
-      return true;
-    }
-
-    if (is_masked_server_card) {
-      if (field_contents_canon.length() < 6) {
-        return true;
-      }
-      if (field_is_autofilled) {
-        int field_contents_length = field_contents_canon.length();
-        DCHECK(field_contents_length >= 4);
-        if (suggestion_canon.find(field_contents_canon.substr(
-                field_contents_length - 4, field_contents_length)) !=
-            std::u16string::npos) {
-          return true;
-        }
-      }
-    }
-
+  if (suggestion_canon.find(field_contents_canon) != std::u16string::npos) {
+    return true;
+  }
+  if (!is_masked_server_card) {
     return false;
   }
-
-  return suggestion_canon.starts_with(field_contents_canon);
+  return field_contents_canon.size() < 6 ||
+         (field_is_autofilled &&
+          suggestion_canon.find(field_contents_canon.substr(
+              field_contents_canon.size() - 4, field_contents_canon.size())) !=
+              std::u16string::npos);
 }
 
 // Normalizes text for comparison based on the type of the field `text` was
@@ -1366,20 +1365,16 @@
       continue;
     }
 #endif  // BUILDFLAG(IS_ANDROID)
-
     std::u16string main_text = GetProfileSuggestionMainText(
         *profile, personal_data_->app_locale(), trigger_field_type);
-
     // Discard profiles that do not have a value for the trigger field.
     if (main_text.empty()) {
       continue;
     }
-
     std::u16string suggestion_canon =
         NormalizeForComparisonForType(main_text, trigger_field_type);
-    if (IsValidSuggestionForFieldContents(
-            suggestion_canon, field_contents_canon, trigger_field_type,
-            /*is_masked_server_card=*/false, field_is_autofilled)) {
+    if (IsValidAddressSuggestionForFieldContents(
+            suggestion_canon, field_contents_canon, trigger_field_type)) {
       matched_profiles.push_back(profile);
     }
   }
@@ -1459,9 +1454,8 @@
     if (!is_manual_fallback && creditcard_field_value.empty()) {
       continue;
     }
-
     // Manual fallback suggestions aren't filtered based on the field's content.
-    if (is_manual_fallback || IsValidSuggestionForFieldContents(
+    if (is_manual_fallback || IsValidPaymentsSuggestionForFieldContents(
                                   base::i18n::ToLower(creditcard_field_value),
                                   field_contents_lower, trigger_field_type,
                                   credit_card.record_type() ==
@@ -1755,9 +1749,8 @@
   suggestion.icon = credit_card.CardIconForAutofillSuggestion();
   // First layer manual fallback entries can't fill forms and thus can't be
   // selected by the user.
-  suggestion.popup_item_id = is_manual_fallback
-                                 ? PopupItemId::kPaymentsEntryNotSelectable
-                                 : PopupItemId::kCreditCardEntry;
+  suggestion.popup_item_id = PopupItemId::kCreditCardEntry;
+  suggestion.is_selectable = !is_manual_fallback;
   suggestion.payload = Suggestion::Guid(credit_card.guid());
 #if BUILDFLAG(IS_ANDROID)
   // The card art icon should always be shown at the start of the suggestion.
@@ -1809,10 +1802,10 @@
   }
 
   suggestion.acceptance_a11y_announcement =
-      suggestion.popup_item_id == PopupItemId::kPaymentsEntryNotSelectable
-          ? l10n_util::GetStringUTF16(
-                IDS_AUTOFILL_A11Y_ANNOUNCE_EXPANDABLE_ONLY_ENTRY)
-          : l10n_util::GetStringUTF16(IDS_AUTOFILL_A11Y_ANNOUNCE_FILLED_FORM);
+      suggestion.is_selectable
+          ? l10n_util::GetStringUTF16(IDS_AUTOFILL_A11Y_ANNOUNCE_FILLED_FORM)
+          : l10n_util::GetStringUTF16(
+                IDS_AUTOFILL_A11Y_ANNOUNCE_EXPANDABLE_ONLY_ENTRY);
 
   return suggestion;
 }
diff --git a/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc b/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc
index a7ba444..4c715d55 100644
--- a/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc
+++ b/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc
@@ -2580,7 +2580,8 @@
 
   // Only the name is displayed on the first line.
   EXPECT_EQ(server_card_suggestion.popup_item_id,
-            PopupItemId::kPaymentsEntryNotSelectable);
+            PopupItemId::kCreditCardEntry);
+  EXPECT_FALSE(server_card_suggestion.is_selectable);
   // For Desktop, split the first line and populate the card name and
   // the last 4 digits separately.
   EXPECT_EQ(server_card_suggestion.main_text.value, u"Visa");
diff --git a/components/autofill/core/browser/browser_autofill_manager.cc b/components/autofill/core/browser/browser_autofill_manager.cc
index 13ec081f..01b45bb4 100644
--- a/components/autofill/core/browser/browser_autofill_manager.cc
+++ b/components/autofill/core/browser/browser_autofill_manager.cc
@@ -291,7 +291,6 @@
     case PopupItemId::kAddressFieldByFieldFilling:
     case PopupItemId::kCreditCardFieldByFieldFilling:
     case PopupItemId::kAddressEntryNotSelectable:
-    case PopupItemId::kPaymentsEntryNotSelectable:
     case PopupItemId::kFillEverythingFromAddressProfile:
     case PopupItemId::kFillExistingPlusAddress:
     case PopupItemId::kFillFullAddress:
diff --git a/components/autofill/core/browser/browser_autofill_manager_unittest.cc b/components/autofill/core/browser/browser_autofill_manager_unittest.cc
index 5b72bc5..29d363c6 100644
--- a/components/autofill/core/browser/browser_autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/browser_autofill_manager_unittest.cc
@@ -1748,11 +1748,10 @@
     GetAutofillSuggestions(
         form, field, AutofillSuggestionTriggerSource::kManualFallbackPayments);
     external_delegate()->CheckSuggestionCount(field.global_id(), 3);
-    EXPECT_TRUE(base::ranges::all_of(
-        external_delegate()->suggestions(), [](const Suggestion& suggestion) {
-          return suggestion.popup_item_id ==
-                 PopupItemId::kPaymentsEntryNotSelectable;
-        }));
+    EXPECT_TRUE(base::ranges::all_of(external_delegate()->suggestions(),
+                                     [](const Suggestion& suggestion) {
+                                       return !suggestion.is_selectable;
+                                     }));
   }
 }
 
@@ -9233,18 +9232,6 @@
 }
 
 TEST_F(BrowserAutofillManagerTest,
-       DidShowSuggestions_CreditCardManualFallback_PreflightFetchingCall) {
-  FormData form = CreateTestAddressFormData();
-  FormsSeen({form});
-
-  EXPECT_CALL(cc_access_manager(), PrepareToFetchCreditCard)
-      .Times(IsCreditCardFidoAuthenticationEnabled() ? 1 : 0);
-  browser_autofill_manager_->DidShowSuggestions(
-      std::vector<PopupItemId>({PopupItemId::kPaymentsEntryNotSelectable}),
-      form, form.fields[0]);
-}
-
-TEST_F(BrowserAutofillManagerTest,
        DidShowSuggestions_AddessSuggestion_NoPreflightFetchingCall) {
   FormData form = CreateTestAddressFormData();
   FormsSeen({form});
diff --git a/components/autofill/core/browser/data_model/autofill_i18n_formatting_expressions.h b/components/autofill/core/browser/data_model/autofill_i18n_formatting_expressions.h
index db5985d..30ef3c3 100644
--- a/components/autofill/core/browser/data_model/autofill_i18n_formatting_expressions.h
+++ b/components/autofill/core/browser/data_model/autofill_i18n_formatting_expressions.h
@@ -19,7 +19,7 @@
 using CountryAndFieldType = std::pair<std::string_view, FieldType>;
 
 // A lookup map for formatting expressions for countries and field types.
-constexpr auto kAutofillFormattingRulesMap =
+inline constexpr auto kAutofillFormattingRulesMap =
     base::MakeFixedFlatMap<CountryAndFieldType, std::u16string_view>({
       {{"BR", ADDRESS_HOME_ADDRESS}, u"${ADDRESS_HOME_STREET_ADDRESS;;}\n${ADDRESS_HOME_DEPENDENT_LOCALITY;;}\n${ADDRESS_HOME_CITY;;} - ${ADDRESS_HOME_STATE;;}\n${ADDRESS_HOME_ZIP;;}"},
       {{"BR", ADDRESS_HOME_STREET_ADDRESS}, u"${ADDRESS_HOME_STREET_LOCATION;;}\n${ADDRESS_HOME_OVERFLOW_AND_LANDMARK;;}"},
@@ -45,4 +45,4 @@
 
 }  // namespace autofill::i18n_model_definition
 
-#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_AUTOFILL_I18N_FORMATTING_EXPRESSIONS_H_
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_AUTOFILL_I18N_FORMATTING_EXPRESSIONS_H_
\ No newline at end of file
diff --git a/components/autofill/core/browser/data_model/autofill_i18n_hierarchies.h b/components/autofill/core/browser/data_model/autofill_i18n_hierarchies.h
index 6f04b4b..f4b0527 100644
--- a/components/autofill/core/browser/data_model/autofill_i18n_hierarchies.h
+++ b/components/autofill/core/browser/data_model/autofill_i18n_hierarchies.h
@@ -16,66 +16,29 @@
 
 namespace autofill::i18n_model_definition {
 // Field types for country BR.
-constexpr FieldType kFieldTypeChildren_BR_ADDRESS_HOME_STREET_LOCATION[] = {
-    ADDRESS_HOME_STREET_NAME, ADDRESS_HOME_HOUSE_NUMBER};
-constexpr FieldType kFieldTypeChildren_BR_ADDRESS_HOME_APT[] = {
-    ADDRESS_HOME_APT_TYPE, ADDRESS_HOME_APT_NUM};
-constexpr FieldType kFieldTypeChildren_BR_ADDRESS_HOME_SUBPREMISE[] = {
-    ADDRESS_HOME_FLOOR, ADDRESS_HOME_APT};
-constexpr FieldType kFieldTypeChildren_BR_ADDRESS_HOME_OVERFLOW[] = {
-    ADDRESS_HOME_SUBPREMISE};
-constexpr FieldType kFieldTypeChildren_BR_ADDRESS_HOME_OVERFLOW_AND_LANDMARK[] =
-    {ADDRESS_HOME_OVERFLOW, ADDRESS_HOME_LANDMARK};
-constexpr FieldType kFieldTypeChildren_BR_ADDRESS_HOME_STREET_ADDRESS[] = {
-    ADDRESS_HOME_STREET_LOCATION, ADDRESS_HOME_OVERFLOW_AND_LANDMARK};
-constexpr FieldType kFieldTypeChildren_BR_ADDRESS_HOME_ADDRESS[] = {
-    ADDRESS_HOME_STREET_ADDRESS,
-    ADDRESS_HOME_CITY,
-    ADDRESS_HOME_DEPENDENT_LOCALITY,
-    ADDRESS_HOME_STATE,
-    ADDRESS_HOME_ZIP,
-    ADDRESS_HOME_COUNTRY};
+inline constexpr FieldType kFieldTypeChildren_BR_ADDRESS_HOME_STREET_LOCATION[] = {ADDRESS_HOME_STREET_NAME, ADDRESS_HOME_HOUSE_NUMBER};
+inline constexpr FieldType kFieldTypeChildren_BR_ADDRESS_HOME_APT[] = {ADDRESS_HOME_APT_TYPE, ADDRESS_HOME_APT_NUM};
+inline constexpr FieldType kFieldTypeChildren_BR_ADDRESS_HOME_SUBPREMISE[] = {ADDRESS_HOME_FLOOR, ADDRESS_HOME_APT};
+inline constexpr FieldType kFieldTypeChildren_BR_ADDRESS_HOME_OVERFLOW[] = {ADDRESS_HOME_SUBPREMISE};
+inline constexpr FieldType kFieldTypeChildren_BR_ADDRESS_HOME_OVERFLOW_AND_LANDMARK[] = {ADDRESS_HOME_OVERFLOW, ADDRESS_HOME_LANDMARK};
+inline constexpr FieldType kFieldTypeChildren_BR_ADDRESS_HOME_STREET_ADDRESS[] = {ADDRESS_HOME_STREET_LOCATION, ADDRESS_HOME_OVERFLOW_AND_LANDMARK};
+inline constexpr FieldType kFieldTypeChildren_BR_ADDRESS_HOME_ADDRESS[] = {ADDRESS_HOME_STREET_ADDRESS, ADDRESS_HOME_CITY, ADDRESS_HOME_DEPENDENT_LOCALITY, ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP, ADDRESS_HOME_COUNTRY};
 // Field types for country MX.
-constexpr FieldType kFieldTypeChildren_MX_ADDRESS_HOME_STREET_LOCATION[] = {
-    ADDRESS_HOME_STREET_NAME, ADDRESS_HOME_HOUSE_NUMBER};
-constexpr FieldType kFieldTypeChildren_MX_ADDRESS_HOME_APT[] = {
-    ADDRESS_HOME_APT_TYPE, ADDRESS_HOME_APT_NUM};
-constexpr FieldType kFieldTypeChildren_MX_ADDRESS_HOME_SUBPREMISE[] = {
-    ADDRESS_HOME_FLOOR, ADDRESS_HOME_APT};
-constexpr FieldType kFieldTypeChildren_MX_ADDRESS_HOME_BETWEEN_STREETS[] = {
-    ADDRESS_HOME_BETWEEN_STREETS_1, ADDRESS_HOME_BETWEEN_STREETS_2};
-constexpr FieldType
-    kFieldTypeChildren_MX_ADDRESS_HOME_BETWEEN_STREETS_OR_LANDMARK[] = {
-        ADDRESS_HOME_LANDMARK, ADDRESS_HOME_BETWEEN_STREETS};
-constexpr FieldType kFieldTypeChildren_MX_ADDRESS_HOME_OVERFLOW[] = {
-    ADDRESS_HOME_BETWEEN_STREETS_OR_LANDMARK};
-constexpr FieldType kFieldTypeChildren_MX_ADDRESS_HOME_STREET_ADDRESS[] = {
-    ADDRESS_HOME_STREET_LOCATION, ADDRESS_HOME_SUBPREMISE,
-    ADDRESS_HOME_OVERFLOW};
-constexpr FieldType kFieldTypeChildren_MX_ADDRESS_HOME_ADDRESS[] = {
-    ADDRESS_HOME_STREET_ADDRESS,
-    ADDRESS_HOME_CITY,
-    ADDRESS_HOME_DEPENDENT_LOCALITY,
-    ADDRESS_HOME_STATE,
-    ADDRESS_HOME_ADMIN_LEVEL2,
-    ADDRESS_HOME_ZIP,
-    ADDRESS_HOME_COUNTRY};
+inline constexpr FieldType kFieldTypeChildren_MX_ADDRESS_HOME_STREET_LOCATION[] = {ADDRESS_HOME_STREET_NAME, ADDRESS_HOME_HOUSE_NUMBER};
+inline constexpr FieldType kFieldTypeChildren_MX_ADDRESS_HOME_APT[] = {ADDRESS_HOME_APT_TYPE, ADDRESS_HOME_APT_NUM};
+inline constexpr FieldType kFieldTypeChildren_MX_ADDRESS_HOME_SUBPREMISE[] = {ADDRESS_HOME_FLOOR, ADDRESS_HOME_APT};
+inline constexpr FieldType kFieldTypeChildren_MX_ADDRESS_HOME_BETWEEN_STREETS[] = {ADDRESS_HOME_BETWEEN_STREETS_1, ADDRESS_HOME_BETWEEN_STREETS_2};
+inline constexpr FieldType kFieldTypeChildren_MX_ADDRESS_HOME_BETWEEN_STREETS_OR_LANDMARK[] = {ADDRESS_HOME_LANDMARK, ADDRESS_HOME_BETWEEN_STREETS};
+inline constexpr FieldType kFieldTypeChildren_MX_ADDRESS_HOME_OVERFLOW[] = {ADDRESS_HOME_BETWEEN_STREETS_OR_LANDMARK};
+inline constexpr FieldType kFieldTypeChildren_MX_ADDRESS_HOME_STREET_ADDRESS[] = {ADDRESS_HOME_STREET_LOCATION, ADDRESS_HOME_SUBPREMISE, ADDRESS_HOME_OVERFLOW};
+inline constexpr FieldType kFieldTypeChildren_MX_ADDRESS_HOME_ADDRESS[] = {ADDRESS_HOME_STREET_ADDRESS, ADDRESS_HOME_CITY, ADDRESS_HOME_DEPENDENT_LOCALITY, ADDRESS_HOME_STATE, ADDRESS_HOME_ADMIN_LEVEL2, ADDRESS_HOME_ZIP, ADDRESS_HOME_COUNTRY};
 // Field types for country US.
-constexpr FieldType kFieldTypeChildren_US_ADDRESS_HOME_ADDRESS[] = {
-    ADDRESS_HOME_STREET_ADDRESS, ADDRESS_HOME_CITY, ADDRESS_HOME_STATE,
-    ADDRESS_HOME_ZIP, ADDRESS_HOME_COUNTRY};
+inline constexpr FieldType kFieldTypeChildren_US_ADDRESS_HOME_ADDRESS[] = {ADDRESS_HOME_STREET_ADDRESS, ADDRESS_HOME_CITY, ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP, ADDRESS_HOME_COUNTRY};
 // Field types for country XX.
-constexpr FieldType kFieldTypeChildren_XX_ADDRESS_HOME_STREET_LOCATION[] = {
-    ADDRESS_HOME_STREET_NAME, ADDRESS_HOME_HOUSE_NUMBER};
-constexpr FieldType kFieldTypeChildren_XX_ADDRESS_HOME_SUBPREMISE[] = {
-    ADDRESS_HOME_FLOOR, ADDRESS_HOME_APT_NUM};
-constexpr FieldType kFieldTypeChildren_XX_ADDRESS_HOME_STREET_ADDRESS[] = {
-    ADDRESS_HOME_STREET_LOCATION, ADDRESS_HOME_SUBPREMISE};
-constexpr FieldType kFieldTypeChildren_XX_ADDRESS_HOME_ADDRESS[] = {
-    ADDRESS_HOME_STREET_ADDRESS,     ADDRESS_HOME_CITY,
-    ADDRESS_HOME_DEPENDENT_LOCALITY, ADDRESS_HOME_STATE,
-    ADDRESS_HOME_ADMIN_LEVEL2,       ADDRESS_HOME_ZIP,
-    ADDRESS_HOME_SORTING_CODE,       ADDRESS_HOME_COUNTRY};
+inline constexpr FieldType kFieldTypeChildren_XX_ADDRESS_HOME_STREET_LOCATION[] = {ADDRESS_HOME_STREET_NAME, ADDRESS_HOME_HOUSE_NUMBER};
+inline constexpr FieldType kFieldTypeChildren_XX_ADDRESS_HOME_SUBPREMISE[] = {ADDRESS_HOME_FLOOR, ADDRESS_HOME_APT_NUM};
+inline constexpr FieldType kFieldTypeChildren_XX_ADDRESS_HOME_STREET_ADDRESS[] = {ADDRESS_HOME_STREET_LOCATION, ADDRESS_HOME_SUBPREMISE};
+inline constexpr FieldType kFieldTypeChildren_XX_ADDRESS_HOME_ADDRESS[] = {ADDRESS_HOME_STREET_ADDRESS, ADDRESS_HOME_CITY, ADDRESS_HOME_DEPENDENT_LOCALITY, ADDRESS_HOME_STATE, ADDRESS_HOME_ADMIN_LEVEL2, ADDRESS_HOME_ZIP, ADDRESS_HOME_SORTING_CODE, ADDRESS_HOME_COUNTRY};
 
 // Contains the properties of a node in the tree. Currently these are the node's
 // type and the list of children.
@@ -86,7 +49,7 @@
 
 // Collection of arrays of node properties for each country.
 // Node properties for country BR.
-constexpr FieldTypeDescription kModel_BR[] = {
+inline constexpr FieldTypeDescription kModel_BR[] = {
     FieldTypeDescription{.field_type = ADDRESS_HOME_STREET_LOCATION, .children = kFieldTypeChildren_BR_ADDRESS_HOME_STREET_LOCATION},
     FieldTypeDescription{.field_type = ADDRESS_HOME_APT, .children = kFieldTypeChildren_BR_ADDRESS_HOME_APT},
     FieldTypeDescription{.field_type = ADDRESS_HOME_SUBPREMISE, .children = kFieldTypeChildren_BR_ADDRESS_HOME_SUBPREMISE},
@@ -95,7 +58,7 @@
     FieldTypeDescription{.field_type = ADDRESS_HOME_STREET_ADDRESS, .children = kFieldTypeChildren_BR_ADDRESS_HOME_STREET_ADDRESS},
     FieldTypeDescription{.field_type = ADDRESS_HOME_ADDRESS, .children = kFieldTypeChildren_BR_ADDRESS_HOME_ADDRESS}};
 // Node properties for country MX.
-constexpr FieldTypeDescription kModel_MX[] = {
+inline constexpr FieldTypeDescription kModel_MX[] = {
     FieldTypeDescription{.field_type = ADDRESS_HOME_STREET_LOCATION, .children = kFieldTypeChildren_MX_ADDRESS_HOME_STREET_LOCATION},
     FieldTypeDescription{.field_type = ADDRESS_HOME_APT, .children = kFieldTypeChildren_MX_ADDRESS_HOME_APT},
     FieldTypeDescription{.field_type = ADDRESS_HOME_SUBPREMISE, .children = kFieldTypeChildren_MX_ADDRESS_HOME_SUBPREMISE},
@@ -105,10 +68,10 @@
     FieldTypeDescription{.field_type = ADDRESS_HOME_STREET_ADDRESS, .children = kFieldTypeChildren_MX_ADDRESS_HOME_STREET_ADDRESS},
     FieldTypeDescription{.field_type = ADDRESS_HOME_ADDRESS, .children = kFieldTypeChildren_MX_ADDRESS_HOME_ADDRESS}};
 // Node properties for country US.
-constexpr FieldTypeDescription kModel_US[] = {
+inline constexpr FieldTypeDescription kModel_US[] = {
     FieldTypeDescription{.field_type = ADDRESS_HOME_ADDRESS, .children = kFieldTypeChildren_US_ADDRESS_HOME_ADDRESS}};
 // Node properties for country XX.
-constexpr FieldTypeDescription kModel_XX[] = {
+inline constexpr FieldTypeDescription kModel_XX[] = {
     FieldTypeDescription{.field_type = ADDRESS_HOME_STREET_LOCATION, .children = kFieldTypeChildren_XX_ADDRESS_HOME_STREET_LOCATION},
     FieldTypeDescription{.field_type = ADDRESS_HOME_SUBPREMISE, .children = kFieldTypeChildren_XX_ADDRESS_HOME_SUBPREMISE},
     FieldTypeDescription{.field_type = ADDRESS_HOME_STREET_ADDRESS, .children = kFieldTypeChildren_XX_ADDRESS_HOME_STREET_ADDRESS},
@@ -118,7 +81,7 @@
 // The lookup map for the autofill hierarchy connections per country. The value
 // type is a span of FieldTypeDescription, representing the connections required to
 // construct the hierarchy model.
-constexpr auto kAutofillModelRules =
+inline constexpr auto kAutofillModelRules =
     base::MakeFixedFlatMap<std::string_view, base::span<const FieldTypeDescription>>({
       {"BR", kModel_BR},
       {"MX", kModel_MX},
@@ -128,4 +91,4 @@
 
 }  // namespace autofill::i18n_model_definition
 
-#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_AUTOFILL_I18N_HIERARCHIES_H_
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_AUTOFILL_I18N_HIERARCHIES_H_
diff --git a/components/autofill/core/browser/data_model/autofill_i18n_parsing_expressions.h b/components/autofill/core/browser/data_model/autofill_i18n_parsing_expressions.h
index aa918cf..8cf112e 100644
--- a/components/autofill/core/browser/data_model/autofill_i18n_parsing_expressions.h
+++ b/components/autofill/core/browser/data_model/autofill_i18n_parsing_expressions.h
@@ -22,78 +22,78 @@
 using CountryAndFieldType = std::pair<std::string_view, FieldType>;
 
 // Section for regular expressions.
-constexpr char kRegularExpression_1[] = "(?m)(?i:(?:^|\\s+))"; // nocheck
-constexpr char kRegularExpression_2[] = "(?m)(?i:(?:^|[,\\s]+))"; // nocheck
-constexpr char kRegularExpression_3[] = "(?m)(?i:(?:남궁|사공|서문|선우|제갈|황보|독고|망절|欧阳|令狐|皇甫|上官|司徒|诸葛|司马|宇文|呼延|端木|張簡|歐陽|諸葛|申屠|尉遲|司馬|軒轅|夏侯))"; // nocheck
-constexpr char kRegularExpression_4[] = "(?m)(?i:\\p{Hangul})"; // nocheck
-constexpr char kRegularExpression_5[] = "(?m)(?i:\\p{Hangul}+)"; // nocheck
-constexpr char kRegularExpression_6[] = "(?m)(?i:(?:・|·| |\\s+))"; // nocheck
-constexpr char kRegularExpression_7[] = "(?m)(?i:(?:Master|Mr\\.?|Miss\\.?|Mrs\\.?|Missus|Ms\\.?|Mx\\.?|M\\.?|Ma'am|Sir|Gentleman|Sire|Mistress|Madam|Ma'am|Dame|Lord|Lady|Esq|Excellency|Excellence|Her Honour|His Honour|Hon\\.?|The Right Honourable|The Most Honourable|Dr\\.?|PhD|DPhil|MD|DO|Prof\\.|Professor|QC|CL|Chancellor|Vice-Chancellor|Principle|Principal|President|Master|Warden|Dean|Regent|Rector|Provost|Director|Chief Executive|Imām|Shaykh|Muftī|Hāfiz|Hāfizah|Qārī|Mawlānā|Hājī|Sayyid|Sayyidah|Sharif|Eminent|Venerable|His Holiness|His Holiness|His All Holiness|His Beatitude|The Most Blessed|His Excellency|His Most Eminent Highness|His Eminence|Most Reverend Eminence|The Most Reverend|His Grace|His Lordship|The Reverend|Fr|Pr|Br|Sr|Elder|Rabbi|The Reverend|Cantor|Chief Rabbi|Grand Rabbi|Rebbetzin|Herr|Frau|Fräulein|Dame|PD|Doktor|Magister|Ingenieur|1lt|1st|2lt|2nd|3rd|admiral|capt|captain|col|cpt|dr|gen|general|lcdr|lt|ltc|ltg|ltjg|maj|major|mg|pastor|prof|rep|reverend|rev|sen|st))"; // nocheck
-constexpr char kRegularExpression_8[] = "(?m)(?i:(?:(?:b\\.a|ba|d\\.d\\.s|dds|ii|iii|iv|ix|jr|m\\.a|m\\.d|md|ms|ph\\.?d|sr|v|vi|vii|viii|x)\\.?))"; // nocheck
-constexpr char kRegularExpression_9[] = "(?m)(?i:(?:\\p{Han}|\\p{Hangul}|\\p{Katakana}|\\p{Hiragana}|\\p{Bopomofo}))"; // nocheck
-constexpr char kRegularExpression_10[] = "(?m)(?i:(?:(?:\\p{Han}|\\p{Hangul}|\\p{Katakana}|\\p{Hiragana}|\\p{Bopomofo})+))"; // nocheck
-constexpr char kRegularExpression_11[] = "(?m)(?i:(?:강전|남궁|독고|동방|망절|사공|서문|선우|소봉|어금|장곡|제갈|황목|황보))"; // nocheck
-constexpr char kRegularExpression_12[] = "(?m)(?i:(?:Aguilar|Alonso|Álvarez|Amador|Betancourt|Blanco|Burgos|Castillo|Castro|Chávez|Colón|Contreras|Cortez|Cruz|Delgado|Diaz|Díaz|Domínguez|Estrada|Fernandez|Fernández|Flores|Fuentes|Garcia|García|Garza|Gil|Gómez|González|Guerrero|Gutiérrez|Guzmán|Hernández|Herrera|Iglesias|Jiménez|Juárez|Lopez|López|Luna|Marín|Marroquín|Martín|Martinez|Martínez|Medina|Méndez|Mendoza|Molina|Morales|Moreno|Muñoz|Narvaez|Navarro|Núñez|Ortega|Ortiz|Ortíz|Peña|Perez|Pérez|Ramírez|Ramos|Reyes|Rivera|Rodriguez|Rodríguez|Rojas|Romero|Rosario|Rubio|Ruiz|Ruíz|Salazar|Sanchez|Sánchez|Santana|Santiago|Santos|Sanz|Serrano|Soto|Suárez|Toro|Torres|Vargas|Vasquez|Vásquez|Vázquez|Velásquez))"; // nocheck
-constexpr char kRegularExpression_13[] = "(?m)(?i:(?:(?:(?:Aguilar|Alonso|Álvarez|Amador|Betancourt|Blanco|Burgos|Castillo|Castro|Chávez|Colón|Contreras|Cortez|Cruz|Delgado|Diaz|Díaz|Domínguez|Estrada|Fernandez|Fernández|Flores|Fuentes|Garcia|García|Garza|Gil|Gómez|González|Guerrero|Gutiérrez|Guzmán|Hernández|Herrera|Iglesias|Jiménez|Juárez|Lopez|López|Luna|Marín|Marroquín|Martín|Martinez|Martínez|Medina|Méndez|Mendoza|Molina|Morales|Moreno|Muñoz|Narvaez|Navarro|Núñez|Ortega|Ortiz|Ortíz|Peña|Perez|Pérez|Ramírez|Ramos|Reyes|Rivera|Rodriguez|Rodríguez|Rojas|Romero|Rosario|Rubio|Ruiz|Ruíz|Salazar|Sanchez|Sánchez|Santana|Santiago|Santos|Sanz|Serrano|Soto|Suárez|Toro|Torres|Vargas|Vasquez|Vásquez|Vázquez|Velásquez)|\\s(?:y|e|i)\\s)))"; // nocheck
-constexpr char kRegularExpression_14[] = "(?m)(?i:(?:^(?:(?:\\p{Han}|\\p{Hangul}|\\p{Katakana}|\\p{Hiragana}|\\p{Bopomofo})+)(?:(?:・|·| |\\s+)(?:(?:\\p{Han}|\\p{Hangul}|\\p{Katakana}|\\p{Hiragana}|\\p{Bopomofo})+))?$))"; // nocheck
-constexpr char kRegularExpression_15[] = "(?m)(?i:(?:[^\\s,]+))"; // nocheck
-constexpr char kRegularExpression_16[] = "(?m)(?i:(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?))"; // nocheck
-constexpr char kRegularExpression_17[] = "(?m)(?i:(?:[^,\\r\\n]+))"; // nocheck
-constexpr char kRegularExpression_18[] = "(?m)(?i:\\s(?:y|e|i)\\s)"; // nocheck
-constexpr char kRegularExpression_19[] = "(?m)(?i:(?:y|e|i))"; // nocheck
-constexpr char kRegularExpression_20[] = "(?m)(?i:(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?)"; // nocheck
-constexpr char kRegularExpression_21[] = "(?m)(?i:^(?:[A-Z]\\.?(?:(?:\\s|-)?[A-Z]\\.?)*)$)"; // nocheck
-constexpr char kRegularExpression_22[] = "(?m)(?i:(?:KM\\s+)?\\d+\\w?)"; // nocheck
-constexpr char kRegularExpression_23[] = "(?m)(?i:(?:apto\\.?|apt\\.?|apartamento|sala nº|sala|conjunto))"; // nocheck
-constexpr char kRegularExpression_24[] = "(?m)(?i:(?:\\d+\\w?\\b|\\w\\b))"; // nocheck
-constexpr char kRegularExpression_25[] = "(?m)(?i:andar)"; // nocheck
-constexpr char kRegularExpression_26[] = "(?m)(?i:(?P<NAME_FULL>(?P<NAME_LAST>(?:(?:\\p{Han}|\\p{Hangul}|\\p{Katakana}|\\p{Hiragana}|\\p{Bopomofo})+))(?:(?:・|·| |\\s+)(?P<NAME_FIRST>(?:(?:\\p{Han}|\\p{Hangul}|\\p{Katakana}|\\p{Hiragana}|\\p{Bopomofo})+)))))"; // nocheck
-constexpr char kRegularExpression_27[] = "(?m)(?i:(?P<NAME_FULL>(?P<NAME_LAST>(?:남궁|사공|서문|선우|제갈|황보|독고|망절|欧阳|令狐|皇甫|上官|司徒|诸葛|司马|宇文|呼延|端木|張簡|歐陽|諸葛|申屠|尉遲|司馬|軒轅|夏侯))(?P<NAME_FIRST>(?:(?:\\p{Han}|\\p{Hangul}|\\p{Katakana}|\\p{Hiragana}|\\p{Bopomofo})+))?))"; // nocheck
-constexpr char kRegularExpression_28[] = "(?m)(?i:(?P<NAME_FULL>(?P<NAME_LAST>(?:\\p{Han}|\\p{Hangul}|\\p{Katakana}|\\p{Hiragana}|\\p{Bopomofo}))(?P<NAME_FIRST>(?:(?:\\p{Han}|\\p{Hangul}|\\p{Katakana}|\\p{Hiragana}|\\p{Bopomofo})+))?))"; // nocheck
-constexpr char kRegularExpression_29[] = "(?m)(?i:(?P<NAME_FULL>(?P<NAME_LAST>(?:강전|남궁|독고|동방|망절|사공|서문|선우|소봉|어금|장곡|제갈|황목|황보))(?P<NAME_FIRST>\\p{Hangul}\\p{Hangul}+)))"; // nocheck
-constexpr char kRegularExpression_30[] = "(?m)(?i:(?P<NAME_FULL>(?P<NAME_LAST>(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?(?:[^\\s,]+))(?:(?:^|\\s+)(?:(?:b\\.a|ba|d\\.d\\.s|dds|ii|iii|iv|ix|jr|m\\.a|m\\.d|md|ms|ph\\.?d|sr|v|vi|vii|viii|x)\\.?))?))"; // nocheck
-constexpr char kRegularExpression_31[] = "(?m)(?i:(?P<NAME_FULL>(?:(?:Master|Mr\\.?|Miss\\.?|Mrs\\.?|Missus|Ms\\.?|Mx\\.?|M\\.?|Ma'am|Sir|Gentleman|Sire|Mistress|Madam|Ma'am|Dame|Lord|Lady|Esq|Excellency|Excellence|Her Honour|His Honour|Hon\\.?|The Right Honourable|The Most Honourable|Dr\\.?|PhD|DPhil|MD|DO|Prof\\.|Professor|QC|CL|Chancellor|Vice-Chancellor|Principle|Principal|President|Master|Warden|Dean|Regent|Rector|Provost|Director|Chief Executive|Imām|Shaykh|Muftī|Hāfiz|Hāfizah|Qārī|Mawlānā|Hājī|Sayyid|Sayyidah|Sharif|Eminent|Venerable|His Holiness|His Holiness|His All Holiness|His Beatitude|The Most Blessed|His Excellency|His Most Eminent Highness|His Eminence|Most Reverend Eminence|The Most Reverend|His Grace|His Lordship|The Reverend|Fr|Pr|Br|Sr|Elder|Rabbi|The Reverend|Cantor|Chief Rabbi|Grand Rabbi|Rebbetzin|Herr|Frau|Fräulein|Dame|PD|Doktor|Magister|Ingenieur|1lt|1st|2lt|2nd|3rd|admiral|capt|captain|col|cpt|dr|gen|general|lcdr|lt|ltc|ltg|ltjg|maj|major|mg|pastor|prof|rep|reverend|rev|sen|st))?(?:(?:^|\\s+)(?P<NAME_FIRST>(?:[^\\s,]+)))?(?:(?:^|\\s+)(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?))??(?:(?:^|\\s+)(?P<NAME_LAST>(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?(?:[^\\s,]+)))(?:(?:^|\\s+)(?:(?:b\\.a|ba|d\\.d\\.s|dds|ii|iii|iv|ix|jr|m\\.a|m\\.d|md|ms|ph\\.?d|sr|v|vi|vii|viii|x)\\.?))?))"; // nocheck
-constexpr char kRegularExpression_32[] = "(?m)(?i:(?P<NAME_FULL>(?:(?:Master|Mr\\.?|Miss\\.?|Mrs\\.?|Missus|Ms\\.?|Mx\\.?|M\\.?|Ma'am|Sir|Gentleman|Sire|Mistress|Madam|Ma'am|Dame|Lord|Lady|Esq|Excellency|Excellence|Her Honour|His Honour|Hon\\.?|The Right Honourable|The Most Honourable|Dr\\.?|PhD|DPhil|MD|DO|Prof\\.|Professor|QC|CL|Chancellor|Vice-Chancellor|Principle|Principal|President|Master|Warden|Dean|Regent|Rector|Provost|Director|Chief Executive|Imām|Shaykh|Muftī|Hāfiz|Hāfizah|Qārī|Mawlānā|Hājī|Sayyid|Sayyidah|Sharif|Eminent|Venerable|His Holiness|His Holiness|His All Holiness|His Beatitude|The Most Blessed|His Excellency|His Most Eminent Highness|His Eminence|Most Reverend Eminence|The Most Reverend|His Grace|His Lordship|The Reverend|Fr|Pr|Br|Sr|Elder|Rabbi|The Reverend|Cantor|Chief Rabbi|Grand Rabbi|Rebbetzin|Herr|Frau|Fräulein|Dame|PD|Doktor|Magister|Ingenieur|1lt|1st|2lt|2nd|3rd|admiral|capt|captain|col|cpt|dr|gen|general|lcdr|lt|ltc|ltg|ltjg|maj|major|mg|pastor|prof|rep|reverend|rev|sen|st))?(?:(?:^|\\s+)(?P<NAME_LAST>(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?(?:[^\\s,]+)))\\s*,\\s*(?P<NAME_FIRST>(?:[^\\s,]+))?(?:(?:^|\\s+)(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?))??))"; // nocheck
-constexpr char kRegularExpression_33[] = "(?m)(?i:(?P<NAME_LAST>(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?(?:[^\\s,]+)(?:(?:^|\\s+)(?:y|e|i))?(?:^|\\s+)(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?(?:[^\\s,]+)))"; // nocheck
-constexpr char kRegularExpression_34[] = "(?m)(?i:(?P<NAME_FULL>(?:(?:Master|Mr\\.?|Miss\\.?|Mrs\\.?|Missus|Ms\\.?|Mx\\.?|M\\.?|Ma'am|Sir|Gentleman|Sire|Mistress|Madam|Ma'am|Dame|Lord|Lady|Esq|Excellency|Excellence|Her Honour|His Honour|Hon\\.?|The Right Honourable|The Most Honourable|Dr\\.?|PhD|DPhil|MD|DO|Prof\\.|Professor|QC|CL|Chancellor|Vice-Chancellor|Principle|Principal|President|Master|Warden|Dean|Regent|Rector|Provost|Director|Chief Executive|Imām|Shaykh|Muftī|Hāfiz|Hāfizah|Qārī|Mawlānā|Hājī|Sayyid|Sayyidah|Sharif|Eminent|Venerable|His Holiness|His Holiness|His All Holiness|His Beatitude|The Most Blessed|His Excellency|His Most Eminent Highness|His Eminence|Most Reverend Eminence|The Most Reverend|His Grace|His Lordship|The Reverend|Fr|Pr|Br|Sr|Elder|Rabbi|The Reverend|Cantor|Chief Rabbi|Grand Rabbi|Rebbetzin|Herr|Frau|Fräulein|Dame|PD|Doktor|Magister|Ingenieur|1lt|1st|2lt|2nd|3rd|admiral|capt|captain|col|cpt|dr|gen|general|lcdr|lt|ltc|ltg|ltjg|maj|major|mg|pastor|prof|rep|reverend|rev|sen|st))?(?:(?:^|\\s+)(?P<NAME_FIRST>(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?)))??(?:(?:^|\\s+)(?P<NAME_LAST>(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?(?:[^\\s,]+)(?:(?:^|\\s+)(?:y|e|i))?(?:^|\\s+)(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?(?:[^\\s,]+)))))"; // nocheck
-constexpr char kRegularExpression_35[] = "(?m)(?i:(?P<NAME_LAST>(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?)))"; // nocheck
-constexpr char kRegularExpression_36[] = "(?m)(?i:\\A\\s*)"; // nocheck
-constexpr char kRegularExpression_37[] = "(?m)(?i:(?P<ADDRESS_HOME_STREET_LOCATION>\\A\\s*(?P<ADDRESS_HOME_STREET_NAME>(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?))(?:(?:,\\s*|\\s+-\\s+|\\s+)(?i:nº\\s+)?(?P<ADDRESS_HOME_HOUSE_NUMBER>(?:KM\\s+)?\\d+\\w?))))"; // nocheck
-constexpr char kRegularExpression_38[] = "(?m)(?i:(?P<ADDRESS_HOME_APT>(?P<ADDRESS_HOME_APT_TYPE>(?:apto\\.?|apt\\.?|apartamento|sala nº|sala|conjunto))(?:(?:^|\\s+)(?P<ADDRESS_HOME_APT_NUM>(?:\\d+\\w?\\b|\\w\\b)))))"; // nocheck
-constexpr char kRegularExpression_39[] = "(?m)(?i:(?:andar\\s*(?P<ADDRESS_HOME_FLOOR>\\d+)))"; // nocheck
-constexpr char kRegularExpression_40[] = "(?m)(?i:(?:(?:[,-]\\s*|^)(?P<ADDRESS_HOME_FLOOR>\\d+)\\s*(?:º\\s*)?andar(?:\\s*[,-]|$)))"; // nocheck
-constexpr char kRegularExpression_41[] = "(?m)(?i:(?:(?:ponto de )?refer[êe]ncia(?::\\s*|\\s+)(?P<ADDRESS_HOME_LANDMARK>[^,\\n]+)))"; // nocheck
-constexpr char kRegularExpression_42[] = "(?m)(?i:(?P<ADDRESS_HOME_APT>(?P<ADDRESS_HOME_APT_TYPE>(?:apto\\.?|apt\\.?|apartamento|sala nº|sala|conjunto))?(?:(?:^|\\s+)(?P<ADDRESS_HOME_APT_NUM>(?:\\d+\\w?\\b|\\w\\b)))))"; // nocheck
-constexpr char kRegularExpression_43[] = "(?m)(?i:(?:(?:S/Num\\.?|S/N|Sin Nombre)|(?:KM\\s+)?\\d+\\w?))"; // nocheck
-constexpr char kRegularExpression_44[] = "(?m)(?i:(?:despacho|loc\\.?|local|int(?:erior|\\.?)|n[uú]m(?:ero|\\.)? int(?:erno|\\.)?|Apartamento|Apto\\.?|Departamento|apto\\.?))"; // nocheck
-constexpr char kRegularExpression_45[] = "(?m)(?i:piso)"; // nocheck
-constexpr char kRegularExpression_46[] = "(?m)(?i:(?P<NAME_FULL>(?:(?:Master|Mr\\.?|Miss\\.?|Mrs\\.?|Missus|Ms\\.?|Mx\\.?|M\\.?|Ma'am|Sir|Gentleman|Sire|Mistress|Madam|Ma'am|Dame|Lord|Lady|Esq|Excellency|Excellence|Her Honour|His Honour|Hon\\.?|The Right Honourable|The Most Honourable|Dr\\.?|PhD|DPhil|MD|DO|Prof\\.|Professor|QC|CL|Chancellor|Vice-Chancellor|Principle|Principal|President|Master|Warden|Dean|Regent|Rector|Provost|Director|Chief Executive|Imām|Shaykh|Muftī|Hāfiz|Hāfizah|Qārī|Mawlānā|Hājī|Sayyid|Sayyidah|Sharif|Eminent|Venerable|His Holiness|His Holiness|His All Holiness|His Beatitude|The Most Blessed|His Excellency|His Most Eminent Highness|His Eminence|Most Reverend Eminence|The Most Reverend|His Grace|His Lordship|The Reverend|Fr|Pr|Br|Sr|Elder|Rabbi|The Reverend|Cantor|Chief Rabbi|Grand Rabbi|Rebbetzin|Herr|Frau|Fräulein|Dame|PD|Doktor|Magister|Ingenieur|1lt|1st|2lt|2nd|3rd|admiral|capt|captain|col|cpt|dr|gen|general|lcdr|lt|ltc|ltg|ltjg|maj|major|mg|pastor|prof|rep|reverend|rev|sen|st))?(?:(?:^|\\s+)(?P<NAME_FIRST>(?:[^\\s,]+)))?(?:(?:^|\\s+)(?P<NAME_MIDDLE>(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?)))??(?:(?:^|\\s+)(?P<NAME_LAST>(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?(?:[^\\s,]+)))(?:(?:^|\\s+)(?:(?:b\\.a|ba|d\\.d\\.s|dds|ii|iii|iv|ix|jr|m\\.a|m\\.d|md|ms|ph\\.?d|sr|v|vi|vii|viii|x)\\.?))?))"; // nocheck
-constexpr char kRegularExpression_47[] = "(?m)(?i:(?P<NAME_FULL>(?:(?:Master|Mr\\.?|Miss\\.?|Mrs\\.?|Missus|Ms\\.?|Mx\\.?|M\\.?|Ma'am|Sir|Gentleman|Sire|Mistress|Madam|Ma'am|Dame|Lord|Lady|Esq|Excellency|Excellence|Her Honour|His Honour|Hon\\.?|The Right Honourable|The Most Honourable|Dr\\.?|PhD|DPhil|MD|DO|Prof\\.|Professor|QC|CL|Chancellor|Vice-Chancellor|Principle|Principal|President|Master|Warden|Dean|Regent|Rector|Provost|Director|Chief Executive|Imām|Shaykh|Muftī|Hāfiz|Hāfizah|Qārī|Mawlānā|Hājī|Sayyid|Sayyidah|Sharif|Eminent|Venerable|His Holiness|His Holiness|His All Holiness|His Beatitude|The Most Blessed|His Excellency|His Most Eminent Highness|His Eminence|Most Reverend Eminence|The Most Reverend|His Grace|His Lordship|The Reverend|Fr|Pr|Br|Sr|Elder|Rabbi|The Reverend|Cantor|Chief Rabbi|Grand Rabbi|Rebbetzin|Herr|Frau|Fräulein|Dame|PD|Doktor|Magister|Ingenieur|1lt|1st|2lt|2nd|3rd|admiral|capt|captain|col|cpt|dr|gen|general|lcdr|lt|ltc|ltg|ltjg|maj|major|mg|pastor|prof|rep|reverend|rev|sen|st))?(?:(?:^|\\s+)(?P<NAME_LAST>(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?(?:[^\\s,]+)))\\s*,\\s*(?P<NAME_FIRST>(?:[^\\s,]+))?(?:(?:^|\\s+)(?P<NAME_MIDDLE>(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?)))??))"; // nocheck
-constexpr char kRegularExpression_48[] = "(?m)(?i:(?P<NAME_LAST>(?P<NAME_LAST_FIRST>(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?(?:[^\\s,]+))(?:(?:^|\\s+)(?P<NAME_LAST_CONJUNCTION>(?:y|e|i)))?(?:(?:^|\\s+)(?P<NAME_LAST_SECOND>(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?(?:[^\\s,]+)))))"; // nocheck
-constexpr char kRegularExpression_49[] = "(?m)(?i:(?P<NAME_FULL>(?:(?:Master|Mr\\.?|Miss\\.?|Mrs\\.?|Missus|Ms\\.?|Mx\\.?|M\\.?|Ma'am|Sir|Gentleman|Sire|Mistress|Madam|Ma'am|Dame|Lord|Lady|Esq|Excellency|Excellence|Her Honour|His Honour|Hon\\.?|The Right Honourable|The Most Honourable|Dr\\.?|PhD|DPhil|MD|DO|Prof\\.|Professor|QC|CL|Chancellor|Vice-Chancellor|Principle|Principal|President|Master|Warden|Dean|Regent|Rector|Provost|Director|Chief Executive|Imām|Shaykh|Muftī|Hāfiz|Hāfizah|Qārī|Mawlānā|Hājī|Sayyid|Sayyidah|Sharif|Eminent|Venerable|His Holiness|His Holiness|His All Holiness|His Beatitude|The Most Blessed|His Excellency|His Most Eminent Highness|His Eminence|Most Reverend Eminence|The Most Reverend|His Grace|His Lordship|The Reverend|Fr|Pr|Br|Sr|Elder|Rabbi|The Reverend|Cantor|Chief Rabbi|Grand Rabbi|Rebbetzin|Herr|Frau|Fräulein|Dame|PD|Doktor|Magister|Ingenieur|1lt|1st|2lt|2nd|3rd|admiral|capt|captain|col|cpt|dr|gen|general|lcdr|lt|ltc|ltg|ltjg|maj|major|mg|pastor|prof|rep|reverend|rev|sen|st))?(?:(?:^|\\s+)(?P<NAME_FIRST>(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?)))??(?:(?:^|\\s+)(?P<NAME_LAST>(?P<NAME_LAST_FIRST>(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?(?:[^\\s,]+))(?:(?:^|\\s+)(?P<NAME_LAST_CONJUNCTION>(?:y|e|i)))?(?:(?:^|\\s+)(?P<NAME_LAST_SECOND>(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?(?:[^\\s,]+)))))))"; // nocheck
-constexpr char kRegularExpression_50[] = "(?m)(?i:(?P<NAME_LAST>(?P<NAME_LAST_SECOND>(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?))))"; // nocheck
-constexpr char kRegularExpression_51[] = "(?m)(?i:(?P<ADDRESS_HOME_STREET_LOCATION>\\A\\s*(?P<ADDRESS_HOME_STREET_NAME>(?:calle\\s+\\d+\\s+[^\\d,\\n\\r]*?|(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?)))(?:[,]?\\s+?(?:(?:#|No\\.?|número\\s)\\s*)?(?P<ADDRESS_HOME_HOUSE_NUMBER>(?:(?:S/Num\\.?|S/N|Sin Nombre)|(?:KM\\s+)?\\d+\\w?)))))"; // nocheck
-constexpr char kRegularExpression_52[] = "(?m)(?i:(?P<ADDRESS_HOME_APT>(?P<ADDRESS_HOME_APT_TYPE>(?:despacho|loc\\.?|local|int(?:erior|\\.?)|n[uú]m(?:ero|\\.)? int(?:erno|\\.)?|Apartamento|Apto\\.?|Departamento|apto\\.?))(?:(?:^|\\s+)(?P<ADDRESS_HOME_APT_NUM>(?:\\d+\\w?\\b|\\w\\b))\\b)))"; // nocheck
-constexpr char kRegularExpression_53[] = "(?m)(?i:(?:piso\\s*(?P<ADDRESS_HOME_FLOOR>\\d+)))"; // nocheck
-constexpr char kRegularExpression_54[] = "(?m)(?i:(?:(?:Cerca del)(?P<ADDRESS_HOME_LANDMARK>[^,\\n]+)))"; // nocheck
-constexpr char kRegularExpression_55[] = "(?m)(?i:(?:\\b(?:x|Entre( Calles)?)\\s+(?P<ADDRESS_HOME_BETWEEN_STREETS>(?P<ADDRESS_HOME_BETWEEN_STREETS_1>(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?))(?:\\s+y\\s+)(?P<ADDRESS_HOME_BETWEEN_STREETS_2>(?:[^,\\r\\n]+)))))"; // nocheck
-constexpr char kRegularExpression_56[] = "(?m)(?i:(?P<ADDRESS_HOME_APT>(?P<ADDRESS_HOME_APT_TYPE>(?:despacho|loc\\.?|local|int(?:erior|\\.?)|n[uú]m(?:ero|\\.)? int(?:erno|\\.)?|Apartamento|Apto\\.?|Departamento|apto\\.?))?(?:(?:^|\\s+)(?P<ADDRESS_HOME_APT_NUM>(?:\\d+\\w?\\b|\\w\\b)))))"; // nocheck
-constexpr char kRegularExpression_57[] = "(?m)(?i:(?:(°|º|\\.|\\s|-)*(floor|flur|fl|og|obergeschoss|ug|untergeschoss|geschoss|andar|piso|º)(\\.|\\s|-)*))"; // nocheck
-constexpr char kRegularExpression_58[] = "(?m)(?i:(?:(?:og|obergeschoss|ug|untergeschoss)?\\d{0,3}\\w?(?:\\.? (?:og|obergeschoss|ug|untergeschoss))?|(?:og|eg|ug)))"; // nocheck
-constexpr char kRegularExpression_59[] = "(?m)(?i:(?:(apt|apartment|wohnung|apto|-)(\\.|\\s|-)*))"; // nocheck
-constexpr char kRegularExpression_60[] = "(?m)(?i:(?:(\\.|\\s|-)*(ª)))"; // nocheck
-constexpr char kRegularExpression_61[] = "(?m)(?i:(?:((no|°|º|number)(\\.|-|\\s)*)?))"; // nocheck
-constexpr char kRegularExpression_62[] = "(?m)(?i:(?:(?:((no|°|º|number)(\\.|-|\\s)*)?)(?P<ADDRESS_HOME_HOUSE_NUMBER>(?:\\d+\\w?))(th\\.|\\.)?)(?:(?:^|\\s+)(?P<ADDRESS_HOME_STREET_NAME>(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?))))"; // nocheck
-constexpr char kRegularExpression_63[] = "(?m)(?i:(?P<ADDRESS_HOME_STREET_NAME>(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?))(?:(?:^|[,\\s]+)(?:((no|°|º|number)(\\.|-|\\s)*)?)(?P<ADDRESS_HOME_HOUSE_NUMBER>(?:\\d+\\w?))(th\\.|\\.)?))"; // nocheck
-constexpr char kRegularExpression_64[] = "(?m)(?i:(?:(?:(apt|apartment|wohnung|apto|-)(\\.|\\s|-)*)(?P<ADDRESS_HOME_APT_NUM>(?:(\\d{0,3}\\w?)))))"; // nocheck
-constexpr char kRegularExpression_65[] = "(?m)(?i:(?:(-\\s*)?(?P<ADDRESS_HOME_APT_NUM>(?:(\\d{1,3}\\w?|\\w)))(?:(\\.|\\s|-)*(ª)))?)"; // nocheck
-constexpr char kRegularExpression_66[] = "(?m)(?i:(?:(?:(°|º|\\.|\\s|-)*(floor|flur|fl|og|obergeschoss|ug|untergeschoss|geschoss|andar|piso|º)(\\.|\\s|-)*)(?P<ADDRESS_HOME_FLOOR>(?:(\\d{0,3}\\w?)))))"; // nocheck
-constexpr char kRegularExpression_67[] = "(?m)(?i:(?:(?P<ADDRESS_HOME_FLOOR>(?:(\\d{1,3}\\w?|\\w)))(?:(°|º|\\.|\\s|-)*(floor|flur|fl|og|obergeschoss|ug|untergeschoss|geschoss|andar|piso|º)(\\.|\\s|-)*)))"; // nocheck
-constexpr char kRegularExpression_68[] = "(?m)(?i:(?P<ADDRESS_HOME_STREET_ADDRESS>(?:(?:(?:((no|°|º|number)(\\.|-|\\s)*)?)(?P<ADDRESS_HOME_HOUSE_NUMBER>(?:\\d+\\w?))(th\\.|\\.)?)(?:(?:^|\\s+)(?P<ADDRESS_HOME_STREET_NAME>(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?)))|(?P<ADDRESS_HOME_STREET_NAME__2>(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?))(?:(?:^|[,\\s]+)(?:((no|°|º|number)(\\.|-|\\s)*)?)(?P<ADDRESS_HOME_HOUSE_NUMBER__2>(?:\\d+\\w?))(th\\.|\\.)?))(?:(?:^|[,\\s]+)(?P<ADDRESS_HOME_SUBPREMISE>(?:(?:(?:(?:(°|º|\\.|\\s|-)*(floor|flur|fl|og|obergeschoss|ug|untergeschoss|geschoss|andar|piso|º)(\\.|\\s|-)*)(?P<ADDRESS_HOME_FLOOR>(?:(\\d{0,3}\\w?))))|(?:(?P<ADDRESS_HOME_FLOOR__2>(?:(\\d{1,3}\\w?|\\w)))(?:(°|º|\\.|\\s|-)*(floor|flur|fl|og|obergeschoss|ug|untergeschoss|geschoss|andar|piso|º)(\\.|\\s|-)*)))(?:(?:^|[,\\s]+)(?:(?:(?:(apt|apartment|wohnung|apto|-)(\\.|\\s|-)*)(?P<ADDRESS_HOME_APT_NUM>(?:(\\d{0,3}\\w?))))|(?:(-\\s*)?(?P<ADDRESS_HOME_APT_NUM__2>(?:(\\d{1,3}\\w?|\\w)))(?:(\\.|\\s|-)*(ª)))?))?|(?:(?:(?:(apt|apartment|wohnung|apto|-)(\\.|\\s|-)*)(?P<ADDRESS_HOME_APT_NUM__3>(?:(\\d{0,3}\\w?))))|(?:(-\\s*)?(?P<ADDRESS_HOME_APT_NUM__4>(?:(\\d{1,3}\\w?|\\w)))(?:(\\.|\\s|-)*(ª)))?))))?))"; // nocheck
+inline constexpr char kRegularExpression_1[] = "(?m)(?i:(?:^|\\s+))"; // nocheck
+inline constexpr char kRegularExpression_2[] = "(?m)(?i:(?:^|[,\\s]+))"; // nocheck
+inline constexpr char kRegularExpression_3[] = "(?m)(?i:(?:남궁|사공|서문|선우|제갈|황보|독고|망절|欧阳|令狐|皇甫|上官|司徒|诸葛|司马|宇文|呼延|端木|張簡|歐陽|諸葛|申屠|尉遲|司馬|軒轅|夏侯))"; // nocheck
+inline constexpr char kRegularExpression_4[] = "(?m)(?i:\\p{Hangul})"; // nocheck
+inline constexpr char kRegularExpression_5[] = "(?m)(?i:\\p{Hangul}+)"; // nocheck
+inline constexpr char kRegularExpression_6[] = "(?m)(?i:(?:・|·| |\\s+))"; // nocheck
+inline constexpr char kRegularExpression_7[] = "(?m)(?i:(?:Master|Mr\\.?|Miss\\.?|Mrs\\.?|Missus|Ms\\.?|Mx\\.?|M\\.?|Ma'am|Sir|Gentleman|Sire|Mistress|Madam|Ma'am|Dame|Lord|Lady|Esq|Excellency|Excellence|Her Honour|His Honour|Hon\\.?|The Right Honourable|The Most Honourable|Dr\\.?|PhD|DPhil|MD|DO|Prof\\.|Professor|QC|CL|Chancellor|Vice-Chancellor|Principle|Principal|President|Master|Warden|Dean|Regent|Rector|Provost|Director|Chief Executive|Imām|Shaykh|Muftī|Hāfiz|Hāfizah|Qārī|Mawlānā|Hājī|Sayyid|Sayyidah|Sharif|Eminent|Venerable|His Holiness|His Holiness|His All Holiness|His Beatitude|The Most Blessed|His Excellency|His Most Eminent Highness|His Eminence|Most Reverend Eminence|The Most Reverend|His Grace|His Lordship|The Reverend|Fr|Pr|Br|Sr|Elder|Rabbi|The Reverend|Cantor|Chief Rabbi|Grand Rabbi|Rebbetzin|Herr|Frau|Fräulein|Dame|PD|Doktor|Magister|Ingenieur|1lt|1st|2lt|2nd|3rd|admiral|capt|captain|col|cpt|dr|gen|general|lcdr|lt|ltc|ltg|ltjg|maj|major|mg|pastor|prof|rep|reverend|rev|sen|st))"; // nocheck
+inline constexpr char kRegularExpression_8[] = "(?m)(?i:(?:(?:b\\.a|ba|d\\.d\\.s|dds|ii|iii|iv|ix|jr|m\\.a|m\\.d|md|ms|ph\\.?d|sr|v|vi|vii|viii|x)\\.?))"; // nocheck
+inline constexpr char kRegularExpression_9[] = "(?m)(?i:(?:\\p{Han}|\\p{Hangul}|\\p{Katakana}|\\p{Hiragana}|\\p{Bopomofo}))"; // nocheck
+inline constexpr char kRegularExpression_10[] = "(?m)(?i:(?:(?:\\p{Han}|\\p{Hangul}|\\p{Katakana}|\\p{Hiragana}|\\p{Bopomofo})+))"; // nocheck
+inline constexpr char kRegularExpression_11[] = "(?m)(?i:(?:강전|남궁|독고|동방|망절|사공|서문|선우|소봉|어금|장곡|제갈|황목|황보))"; // nocheck
+inline constexpr char kRegularExpression_12[] = "(?m)(?i:(?:Aguilar|Alonso|Álvarez|Amador|Betancourt|Blanco|Burgos|Castillo|Castro|Chávez|Colón|Contreras|Cortez|Cruz|Delgado|Diaz|Díaz|Domínguez|Estrada|Fernandez|Fernández|Flores|Fuentes|Garcia|García|Garza|Gil|Gómez|González|Guerrero|Gutiérrez|Guzmán|Hernández|Herrera|Iglesias|Jiménez|Juárez|Lopez|López|Luna|Marín|Marroquín|Martín|Martinez|Martínez|Medina|Méndez|Mendoza|Molina|Morales|Moreno|Muñoz|Narvaez|Navarro|Núñez|Ortega|Ortiz|Ortíz|Peña|Perez|Pérez|Ramírez|Ramos|Reyes|Rivera|Rodriguez|Rodríguez|Rojas|Romero|Rosario|Rubio|Ruiz|Ruíz|Salazar|Sanchez|Sánchez|Santana|Santiago|Santos|Sanz|Serrano|Soto|Suárez|Toro|Torres|Vargas|Vasquez|Vásquez|Vázquez|Velásquez))"; // nocheck
+inline constexpr char kRegularExpression_13[] = "(?m)(?i:(?:(?:(?:Aguilar|Alonso|Álvarez|Amador|Betancourt|Blanco|Burgos|Castillo|Castro|Chávez|Colón|Contreras|Cortez|Cruz|Delgado|Diaz|Díaz|Domínguez|Estrada|Fernandez|Fernández|Flores|Fuentes|Garcia|García|Garza|Gil|Gómez|González|Guerrero|Gutiérrez|Guzmán|Hernández|Herrera|Iglesias|Jiménez|Juárez|Lopez|López|Luna|Marín|Marroquín|Martín|Martinez|Martínez|Medina|Méndez|Mendoza|Molina|Morales|Moreno|Muñoz|Narvaez|Navarro|Núñez|Ortega|Ortiz|Ortíz|Peña|Perez|Pérez|Ramírez|Ramos|Reyes|Rivera|Rodriguez|Rodríguez|Rojas|Romero|Rosario|Rubio|Ruiz|Ruíz|Salazar|Sanchez|Sánchez|Santana|Santiago|Santos|Sanz|Serrano|Soto|Suárez|Toro|Torres|Vargas|Vasquez|Vásquez|Vázquez|Velásquez)|\\s(?:y|e|i)\\s)))"; // nocheck
+inline constexpr char kRegularExpression_14[] = "(?m)(?i:(?:^(?:(?:\\p{Han}|\\p{Hangul}|\\p{Katakana}|\\p{Hiragana}|\\p{Bopomofo})+)(?:(?:・|·| |\\s+)(?:(?:\\p{Han}|\\p{Hangul}|\\p{Katakana}|\\p{Hiragana}|\\p{Bopomofo})+))?$))"; // nocheck
+inline constexpr char kRegularExpression_15[] = "(?m)(?i:(?:[^\\s,]+))"; // nocheck
+inline constexpr char kRegularExpression_16[] = "(?m)(?i:(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?))"; // nocheck
+inline constexpr char kRegularExpression_17[] = "(?m)(?i:(?:[^,\\r\\n]+))"; // nocheck
+inline constexpr char kRegularExpression_18[] = "(?m)(?i:\\s(?:y|e|i)\\s)"; // nocheck
+inline constexpr char kRegularExpression_19[] = "(?m)(?i:(?:y|e|i))"; // nocheck
+inline constexpr char kRegularExpression_20[] = "(?m)(?i:(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?)"; // nocheck
+inline constexpr char kRegularExpression_21[] = "(?m)(?i:^(?:[A-Z]\\.?(?:(?:\\s|-)?[A-Z]\\.?)*)$)"; // nocheck
+inline constexpr char kRegularExpression_22[] = "(?m)(?i:(?:KM\\s+)?\\d+\\w?)"; // nocheck
+inline constexpr char kRegularExpression_23[] = "(?m)(?i:(?:apto\\.?|apt\\.?|apartamento|sala nº|sala|conjunto))"; // nocheck
+inline constexpr char kRegularExpression_24[] = "(?m)(?i:(?:\\d+\\w?\\b|\\w\\b))"; // nocheck
+inline constexpr char kRegularExpression_25[] = "(?m)(?i:andar)"; // nocheck
+inline constexpr char kRegularExpression_26[] = "(?m)(?i:(?P<NAME_FULL>(?P<NAME_LAST>(?:(?:\\p{Han}|\\p{Hangul}|\\p{Katakana}|\\p{Hiragana}|\\p{Bopomofo})+))(?:(?:・|·| |\\s+)(?P<NAME_FIRST>(?:(?:\\p{Han}|\\p{Hangul}|\\p{Katakana}|\\p{Hiragana}|\\p{Bopomofo})+)))))"; // nocheck
+inline constexpr char kRegularExpression_27[] = "(?m)(?i:(?P<NAME_FULL>(?P<NAME_LAST>(?:남궁|사공|서문|선우|제갈|황보|독고|망절|欧阳|令狐|皇甫|上官|司徒|诸葛|司马|宇文|呼延|端木|張簡|歐陽|諸葛|申屠|尉遲|司馬|軒轅|夏侯))(?P<NAME_FIRST>(?:(?:\\p{Han}|\\p{Hangul}|\\p{Katakana}|\\p{Hiragana}|\\p{Bopomofo})+))?))"; // nocheck
+inline constexpr char kRegularExpression_28[] = "(?m)(?i:(?P<NAME_FULL>(?P<NAME_LAST>(?:\\p{Han}|\\p{Hangul}|\\p{Katakana}|\\p{Hiragana}|\\p{Bopomofo}))(?P<NAME_FIRST>(?:(?:\\p{Han}|\\p{Hangul}|\\p{Katakana}|\\p{Hiragana}|\\p{Bopomofo})+))?))"; // nocheck
+inline constexpr char kRegularExpression_29[] = "(?m)(?i:(?P<NAME_FULL>(?P<NAME_LAST>(?:강전|남궁|독고|동방|망절|사공|서문|선우|소봉|어금|장곡|제갈|황목|황보))(?P<NAME_FIRST>\\p{Hangul}\\p{Hangul}+)))"; // nocheck
+inline constexpr char kRegularExpression_30[] = "(?m)(?i:(?P<NAME_FULL>(?P<NAME_LAST>(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?(?:[^\\s,]+))(?:(?:^|\\s+)(?:(?:b\\.a|ba|d\\.d\\.s|dds|ii|iii|iv|ix|jr|m\\.a|m\\.d|md|ms|ph\\.?d|sr|v|vi|vii|viii|x)\\.?))?))"; // nocheck
+inline constexpr char kRegularExpression_31[] = "(?m)(?i:(?P<NAME_FULL>(?:(?:Master|Mr\\.?|Miss\\.?|Mrs\\.?|Missus|Ms\\.?|Mx\\.?|M\\.?|Ma'am|Sir|Gentleman|Sire|Mistress|Madam|Ma'am|Dame|Lord|Lady|Esq|Excellency|Excellence|Her Honour|His Honour|Hon\\.?|The Right Honourable|The Most Honourable|Dr\\.?|PhD|DPhil|MD|DO|Prof\\.|Professor|QC|CL|Chancellor|Vice-Chancellor|Principle|Principal|President|Master|Warden|Dean|Regent|Rector|Provost|Director|Chief Executive|Imām|Shaykh|Muftī|Hāfiz|Hāfizah|Qārī|Mawlānā|Hājī|Sayyid|Sayyidah|Sharif|Eminent|Venerable|His Holiness|His Holiness|His All Holiness|His Beatitude|The Most Blessed|His Excellency|His Most Eminent Highness|His Eminence|Most Reverend Eminence|The Most Reverend|His Grace|His Lordship|The Reverend|Fr|Pr|Br|Sr|Elder|Rabbi|The Reverend|Cantor|Chief Rabbi|Grand Rabbi|Rebbetzin|Herr|Frau|Fräulein|Dame|PD|Doktor|Magister|Ingenieur|1lt|1st|2lt|2nd|3rd|admiral|capt|captain|col|cpt|dr|gen|general|lcdr|lt|ltc|ltg|ltjg|maj|major|mg|pastor|prof|rep|reverend|rev|sen|st))?(?:(?:^|\\s+)(?P<NAME_FIRST>(?:[^\\s,]+)))?(?:(?:^|\\s+)(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?))??(?:(?:^|\\s+)(?P<NAME_LAST>(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?(?:[^\\s,]+)))(?:(?:^|\\s+)(?:(?:b\\.a|ba|d\\.d\\.s|dds|ii|iii|iv|ix|jr|m\\.a|m\\.d|md|ms|ph\\.?d|sr|v|vi|vii|viii|x)\\.?))?))"; // nocheck
+inline constexpr char kRegularExpression_32[] = "(?m)(?i:(?P<NAME_FULL>(?:(?:Master|Mr\\.?|Miss\\.?|Mrs\\.?|Missus|Ms\\.?|Mx\\.?|M\\.?|Ma'am|Sir|Gentleman|Sire|Mistress|Madam|Ma'am|Dame|Lord|Lady|Esq|Excellency|Excellence|Her Honour|His Honour|Hon\\.?|The Right Honourable|The Most Honourable|Dr\\.?|PhD|DPhil|MD|DO|Prof\\.|Professor|QC|CL|Chancellor|Vice-Chancellor|Principle|Principal|President|Master|Warden|Dean|Regent|Rector|Provost|Director|Chief Executive|Imām|Shaykh|Muftī|Hāfiz|Hāfizah|Qārī|Mawlānā|Hājī|Sayyid|Sayyidah|Sharif|Eminent|Venerable|His Holiness|His Holiness|His All Holiness|His Beatitude|The Most Blessed|His Excellency|His Most Eminent Highness|His Eminence|Most Reverend Eminence|The Most Reverend|His Grace|His Lordship|The Reverend|Fr|Pr|Br|Sr|Elder|Rabbi|The Reverend|Cantor|Chief Rabbi|Grand Rabbi|Rebbetzin|Herr|Frau|Fräulein|Dame|PD|Doktor|Magister|Ingenieur|1lt|1st|2lt|2nd|3rd|admiral|capt|captain|col|cpt|dr|gen|general|lcdr|lt|ltc|ltg|ltjg|maj|major|mg|pastor|prof|rep|reverend|rev|sen|st))?(?:(?:^|\\s+)(?P<NAME_LAST>(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?(?:[^\\s,]+)))\\s*,\\s*(?P<NAME_FIRST>(?:[^\\s,]+))?(?:(?:^|\\s+)(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?))??))"; // nocheck
+inline constexpr char kRegularExpression_33[] = "(?m)(?i:(?P<NAME_LAST>(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?(?:[^\\s,]+)(?:(?:^|\\s+)(?:y|e|i))?(?:^|\\s+)(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?(?:[^\\s,]+)))"; // nocheck
+inline constexpr char kRegularExpression_34[] = "(?m)(?i:(?P<NAME_FULL>(?:(?:Master|Mr\\.?|Miss\\.?|Mrs\\.?|Missus|Ms\\.?|Mx\\.?|M\\.?|Ma'am|Sir|Gentleman|Sire|Mistress|Madam|Ma'am|Dame|Lord|Lady|Esq|Excellency|Excellence|Her Honour|His Honour|Hon\\.?|The Right Honourable|The Most Honourable|Dr\\.?|PhD|DPhil|MD|DO|Prof\\.|Professor|QC|CL|Chancellor|Vice-Chancellor|Principle|Principal|President|Master|Warden|Dean|Regent|Rector|Provost|Director|Chief Executive|Imām|Shaykh|Muftī|Hāfiz|Hāfizah|Qārī|Mawlānā|Hājī|Sayyid|Sayyidah|Sharif|Eminent|Venerable|His Holiness|His Holiness|His All Holiness|His Beatitude|The Most Blessed|His Excellency|His Most Eminent Highness|His Eminence|Most Reverend Eminence|The Most Reverend|His Grace|His Lordship|The Reverend|Fr|Pr|Br|Sr|Elder|Rabbi|The Reverend|Cantor|Chief Rabbi|Grand Rabbi|Rebbetzin|Herr|Frau|Fräulein|Dame|PD|Doktor|Magister|Ingenieur|1lt|1st|2lt|2nd|3rd|admiral|capt|captain|col|cpt|dr|gen|general|lcdr|lt|ltc|ltg|ltjg|maj|major|mg|pastor|prof|rep|reverend|rev|sen|st))?(?:(?:^|\\s+)(?P<NAME_FIRST>(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?)))??(?:(?:^|\\s+)(?P<NAME_LAST>(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?(?:[^\\s,]+)(?:(?:^|\\s+)(?:y|e|i))?(?:^|\\s+)(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?(?:[^\\s,]+)))))"; // nocheck
+inline constexpr char kRegularExpression_35[] = "(?m)(?i:(?P<NAME_LAST>(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?)))"; // nocheck
+inline constexpr char kRegularExpression_36[] = "(?m)(?i:\\A\\s*)"; // nocheck
+inline constexpr char kRegularExpression_37[] = "(?m)(?i:(?P<ADDRESS_HOME_STREET_LOCATION>\\A\\s*(?P<ADDRESS_HOME_STREET_NAME>(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?))(?:(?:,\\s*|\\s+-\\s+|\\s+)(?i:nº\\s+)?(?P<ADDRESS_HOME_HOUSE_NUMBER>(?:KM\\s+)?\\d+\\w?))))"; // nocheck
+inline constexpr char kRegularExpression_38[] = "(?m)(?i:(?P<ADDRESS_HOME_APT>(?P<ADDRESS_HOME_APT_TYPE>(?:apto\\.?|apt\\.?|apartamento|sala nº|sala|conjunto))(?:(?:^|\\s+)(?P<ADDRESS_HOME_APT_NUM>(?:\\d+\\w?\\b|\\w\\b)))))"; // nocheck
+inline constexpr char kRegularExpression_39[] = "(?m)(?i:(?:andar\\s*(?P<ADDRESS_HOME_FLOOR>\\d+)))"; // nocheck
+inline constexpr char kRegularExpression_40[] = "(?m)(?i:(?:(?:[,-]\\s*|^)(?P<ADDRESS_HOME_FLOOR>\\d+)\\s*(?:º\\s*)?andar(?:\\s*[,-]|$)))"; // nocheck
+inline constexpr char kRegularExpression_41[] = "(?m)(?i:(?:(?:ponto de )?refer[êe]ncia(?::\\s*|\\s+)(?P<ADDRESS_HOME_LANDMARK>[^,\\n]+)))"; // nocheck
+inline constexpr char kRegularExpression_42[] = "(?m)(?i:(?P<ADDRESS_HOME_APT>(?P<ADDRESS_HOME_APT_TYPE>(?:apto\\.?|apt\\.?|apartamento|sala nº|sala|conjunto))?(?:(?:^|\\s+)(?P<ADDRESS_HOME_APT_NUM>(?:\\d+\\w?\\b|\\w\\b)))))"; // nocheck
+inline constexpr char kRegularExpression_43[] = "(?m)(?i:(?:(?:S/Num\\.?|S/N|Sin Nombre)|(?:KM\\s+)?\\d+\\w?))"; // nocheck
+inline constexpr char kRegularExpression_44[] = "(?m)(?i:(?:despacho|loc\\.?|local|int(?:erior|\\.?)|n[uú]m(?:ero|\\.)? int(?:erno|\\.)?|Apartamento|Apto\\.?|Departamento|apto\\.?))"; // nocheck
+inline constexpr char kRegularExpression_45[] = "(?m)(?i:piso)"; // nocheck
+inline constexpr char kRegularExpression_46[] = "(?m)(?i:(?P<NAME_FULL>(?:(?:Master|Mr\\.?|Miss\\.?|Mrs\\.?|Missus|Ms\\.?|Mx\\.?|M\\.?|Ma'am|Sir|Gentleman|Sire|Mistress|Madam|Ma'am|Dame|Lord|Lady|Esq|Excellency|Excellence|Her Honour|His Honour|Hon\\.?|The Right Honourable|The Most Honourable|Dr\\.?|PhD|DPhil|MD|DO|Prof\\.|Professor|QC|CL|Chancellor|Vice-Chancellor|Principle|Principal|President|Master|Warden|Dean|Regent|Rector|Provost|Director|Chief Executive|Imām|Shaykh|Muftī|Hāfiz|Hāfizah|Qārī|Mawlānā|Hājī|Sayyid|Sayyidah|Sharif|Eminent|Venerable|His Holiness|His Holiness|His All Holiness|His Beatitude|The Most Blessed|His Excellency|His Most Eminent Highness|His Eminence|Most Reverend Eminence|The Most Reverend|His Grace|His Lordship|The Reverend|Fr|Pr|Br|Sr|Elder|Rabbi|The Reverend|Cantor|Chief Rabbi|Grand Rabbi|Rebbetzin|Herr|Frau|Fräulein|Dame|PD|Doktor|Magister|Ingenieur|1lt|1st|2lt|2nd|3rd|admiral|capt|captain|col|cpt|dr|gen|general|lcdr|lt|ltc|ltg|ltjg|maj|major|mg|pastor|prof|rep|reverend|rev|sen|st))?(?:(?:^|\\s+)(?P<NAME_FIRST>(?:[^\\s,]+)))?(?:(?:^|\\s+)(?P<NAME_MIDDLE>(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?)))??(?:(?:^|\\s+)(?P<NAME_LAST>(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?(?:[^\\s,]+)))(?:(?:^|\\s+)(?:(?:b\\.a|ba|d\\.d\\.s|dds|ii|iii|iv|ix|jr|m\\.a|m\\.d|md|ms|ph\\.?d|sr|v|vi|vii|viii|x)\\.?))?))"; // nocheck
+inline constexpr char kRegularExpression_47[] = "(?m)(?i:(?P<NAME_FULL>(?:(?:Master|Mr\\.?|Miss\\.?|Mrs\\.?|Missus|Ms\\.?|Mx\\.?|M\\.?|Ma'am|Sir|Gentleman|Sire|Mistress|Madam|Ma'am|Dame|Lord|Lady|Esq|Excellency|Excellence|Her Honour|His Honour|Hon\\.?|The Right Honourable|The Most Honourable|Dr\\.?|PhD|DPhil|MD|DO|Prof\\.|Professor|QC|CL|Chancellor|Vice-Chancellor|Principle|Principal|President|Master|Warden|Dean|Regent|Rector|Provost|Director|Chief Executive|Imām|Shaykh|Muftī|Hāfiz|Hāfizah|Qārī|Mawlānā|Hājī|Sayyid|Sayyidah|Sharif|Eminent|Venerable|His Holiness|His Holiness|His All Holiness|His Beatitude|The Most Blessed|His Excellency|His Most Eminent Highness|His Eminence|Most Reverend Eminence|The Most Reverend|His Grace|His Lordship|The Reverend|Fr|Pr|Br|Sr|Elder|Rabbi|The Reverend|Cantor|Chief Rabbi|Grand Rabbi|Rebbetzin|Herr|Frau|Fräulein|Dame|PD|Doktor|Magister|Ingenieur|1lt|1st|2lt|2nd|3rd|admiral|capt|captain|col|cpt|dr|gen|general|lcdr|lt|ltc|ltg|ltjg|maj|major|mg|pastor|prof|rep|reverend|rev|sen|st))?(?:(?:^|\\s+)(?P<NAME_LAST>(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?(?:[^\\s,]+)))\\s*,\\s*(?P<NAME_FIRST>(?:[^\\s,]+))?(?:(?:^|\\s+)(?P<NAME_MIDDLE>(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?)))??))"; // nocheck
+inline constexpr char kRegularExpression_48[] = "(?m)(?i:(?P<NAME_LAST>(?P<NAME_LAST_FIRST>(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?(?:[^\\s,]+))(?:(?:^|\\s+)(?P<NAME_LAST_CONJUNCTION>(?:y|e|i)))?(?:(?:^|\\s+)(?P<NAME_LAST_SECOND>(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?(?:[^\\s,]+)))))"; // nocheck
+inline constexpr char kRegularExpression_49[] = "(?m)(?i:(?P<NAME_FULL>(?:(?:Master|Mr\\.?|Miss\\.?|Mrs\\.?|Missus|Ms\\.?|Mx\\.?|M\\.?|Ma'am|Sir|Gentleman|Sire|Mistress|Madam|Ma'am|Dame|Lord|Lady|Esq|Excellency|Excellence|Her Honour|His Honour|Hon\\.?|The Right Honourable|The Most Honourable|Dr\\.?|PhD|DPhil|MD|DO|Prof\\.|Professor|QC|CL|Chancellor|Vice-Chancellor|Principle|Principal|President|Master|Warden|Dean|Regent|Rector|Provost|Director|Chief Executive|Imām|Shaykh|Muftī|Hāfiz|Hāfizah|Qārī|Mawlānā|Hājī|Sayyid|Sayyidah|Sharif|Eminent|Venerable|His Holiness|His Holiness|His All Holiness|His Beatitude|The Most Blessed|His Excellency|His Most Eminent Highness|His Eminence|Most Reverend Eminence|The Most Reverend|His Grace|His Lordship|The Reverend|Fr|Pr|Br|Sr|Elder|Rabbi|The Reverend|Cantor|Chief Rabbi|Grand Rabbi|Rebbetzin|Herr|Frau|Fräulein|Dame|PD|Doktor|Magister|Ingenieur|1lt|1st|2lt|2nd|3rd|admiral|capt|captain|col|cpt|dr|gen|general|lcdr|lt|ltc|ltg|ltjg|maj|major|mg|pastor|prof|rep|reverend|rev|sen|st))?(?:(?:^|\\s+)(?P<NAME_FIRST>(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?)))??(?:(?:^|\\s+)(?P<NAME_LAST>(?P<NAME_LAST_FIRST>(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?(?:[^\\s,]+))(?:(?:^|\\s+)(?P<NAME_LAST_CONJUNCTION>(?:y|e|i)))?(?:(?:^|\\s+)(?P<NAME_LAST_SECOND>(?:(?:a|ab|af|av|ap|abu|aït|al|ālam|aust|austre|bar|bath|bat|ben|bin|ibn|bet|bint|binti|binte|da|das|de|degli|dele|del|du|della|der|di|dos|du|e|el|fetch|vetch|fitz|i??|kil|gil|de le|de la|la|le|lille|lu|m|mac|mc|mck|mhic|mic|mala|mellom|myljom|na|ned|nedre|neder|nic|ni|nin|nord|norr|ny|o|ua|ui|opp|upp|öfver|ost|öst|öster|øst|øst|østre|över|øvste|øvre|øver|öz|pour|putra|putri|setia|tor|söder|sør|sønder|sør|syd|søndre|syndre|søre|ter|ter|tre|van|van der|väst|väster|verch|erch|vest|vestre|vesle|vetle|von|zu|von und zu)\\s)?(?:[^\\s,]+)))))))"; // nocheck
+inline constexpr char kRegularExpression_50[] = "(?m)(?i:(?P<NAME_LAST>(?P<NAME_LAST_SECOND>(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?))))"; // nocheck
+inline constexpr char kRegularExpression_51[] = "(?m)(?i:(?P<ADDRESS_HOME_STREET_LOCATION>\\A\\s*(?P<ADDRESS_HOME_STREET_NAME>(?:calle\\s+\\d+\\s+[^\\d,\\n\\r]*?|(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?)))(?:[,]?\\s+?(?:(?:#|No\\.?|número\\s)\\s*)?(?P<ADDRESS_HOME_HOUSE_NUMBER>(?:(?:S/Num\\.?|S/N|Sin Nombre)|(?:KM\\s+)?\\d+\\w?)))))"; // nocheck
+inline constexpr char kRegularExpression_52[] = "(?m)(?i:(?P<ADDRESS_HOME_APT>(?P<ADDRESS_HOME_APT_TYPE>(?:despacho|loc\\.?|local|int(?:erior|\\.?)|n[uú]m(?:ero|\\.)? int(?:erno|\\.)?|Apartamento|Apto\\.?|Departamento|apto\\.?))(?:(?:^|\\s+)(?P<ADDRESS_HOME_APT_NUM>(?:\\d+\\w?\\b|\\w\\b))\\b)))"; // nocheck
+inline constexpr char kRegularExpression_53[] = "(?m)(?i:(?:piso\\s*(?P<ADDRESS_HOME_FLOOR>\\d+)))"; // nocheck
+inline constexpr char kRegularExpression_54[] = "(?m)(?i:(?:(?:Cerca del)(?P<ADDRESS_HOME_LANDMARK>[^,\\n]+)))"; // nocheck
+inline constexpr char kRegularExpression_55[] = "(?m)(?i:(?:\\b(?:x|Entre( Calles)?)\\s+(?P<ADDRESS_HOME_BETWEEN_STREETS>(?P<ADDRESS_HOME_BETWEEN_STREETS_1>(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?))(?:\\s+y\\s+)(?P<ADDRESS_HOME_BETWEEN_STREETS_2>(?:[^,\\r\\n]+)))))"; // nocheck
+inline constexpr char kRegularExpression_56[] = "(?m)(?i:(?P<ADDRESS_HOME_APT>(?P<ADDRESS_HOME_APT_TYPE>(?:despacho|loc\\.?|local|int(?:erior|\\.?)|n[uú]m(?:ero|\\.)? int(?:erno|\\.)?|Apartamento|Apto\\.?|Departamento|apto\\.?))?(?:(?:^|\\s+)(?P<ADDRESS_HOME_APT_NUM>(?:\\d+\\w?\\b|\\w\\b)))))"; // nocheck
+inline constexpr char kRegularExpression_57[] = "(?m)(?i:(?:(°|º|\\.|\\s|-)*(floor|flur|fl|og|obergeschoss|ug|untergeschoss|geschoss|andar|piso|º)(\\.|\\s|-)*))"; // nocheck
+inline constexpr char kRegularExpression_58[] = "(?m)(?i:(?:(?:og|obergeschoss|ug|untergeschoss)?\\d{0,3}\\w?(?:\\.? (?:og|obergeschoss|ug|untergeschoss))?|(?:og|eg|ug)))"; // nocheck
+inline constexpr char kRegularExpression_59[] = "(?m)(?i:(?:(apt|apartment|wohnung|apto|-)(\\.|\\s|-)*))"; // nocheck
+inline constexpr char kRegularExpression_60[] = "(?m)(?i:(?:(\\.|\\s|-)*(ª)))"; // nocheck
+inline constexpr char kRegularExpression_61[] = "(?m)(?i:(?:((no|°|º|number)(\\.|-|\\s)*)?))"; // nocheck
+inline constexpr char kRegularExpression_62[] = "(?m)(?i:(?:(?:((no|°|º|number)(\\.|-|\\s)*)?)(?P<ADDRESS_HOME_HOUSE_NUMBER>(?:\\d+\\w?))(th\\.|\\.)?)(?:(?:^|\\s+)(?P<ADDRESS_HOME_STREET_NAME>(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?))))"; // nocheck
+inline constexpr char kRegularExpression_63[] = "(?m)(?i:(?P<ADDRESS_HOME_STREET_NAME>(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?))(?:(?:^|[,\\s]+)(?:((no|°|º|number)(\\.|-|\\s)*)?)(?P<ADDRESS_HOME_HOUSE_NUMBER>(?:\\d+\\w?))(th\\.|\\.)?))"; // nocheck
+inline constexpr char kRegularExpression_64[] = "(?m)(?i:(?:(?:(apt|apartment|wohnung|apto|-)(\\.|\\s|-)*)(?P<ADDRESS_HOME_APT_NUM>(?:(\\d{0,3}\\w?)))))"; // nocheck
+inline constexpr char kRegularExpression_65[] = "(?m)(?i:(?:(-\\s*)?(?P<ADDRESS_HOME_APT_NUM>(?:(\\d{1,3}\\w?|\\w)))(?:(\\.|\\s|-)*(ª)))?)"; // nocheck
+inline constexpr char kRegularExpression_66[] = "(?m)(?i:(?:(?:(°|º|\\.|\\s|-)*(floor|flur|fl|og|obergeschoss|ug|untergeschoss|geschoss|andar|piso|º)(\\.|\\s|-)*)(?P<ADDRESS_HOME_FLOOR>(?:(\\d{0,3}\\w?)))))"; // nocheck
+inline constexpr char kRegularExpression_67[] = "(?m)(?i:(?:(?P<ADDRESS_HOME_FLOOR>(?:(\\d{1,3}\\w?|\\w)))(?:(°|º|\\.|\\s|-)*(floor|flur|fl|og|obergeschoss|ug|untergeschoss|geschoss|andar|piso|º)(\\.|\\s|-)*)))"; // nocheck
+inline constexpr char kRegularExpression_68[] = "(?m)(?i:(?P<ADDRESS_HOME_STREET_ADDRESS>(?:(?:(?:((no|°|º|number)(\\.|-|\\s)*)?)(?P<ADDRESS_HOME_HOUSE_NUMBER>(?:\\d+\\w?))(th\\.|\\.)?)(?:(?:^|\\s+)(?P<ADDRESS_HOME_STREET_NAME>(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?)))|(?P<ADDRESS_HOME_STREET_NAME__2>(?:[^\\s,]+(?:[^\\S\\r\\n]+[^\\s,]+)*?))(?:(?:^|[,\\s]+)(?:((no|°|º|number)(\\.|-|\\s)*)?)(?P<ADDRESS_HOME_HOUSE_NUMBER__2>(?:\\d+\\w?))(th\\.|\\.)?))(?:(?:^|[,\\s]+)(?P<ADDRESS_HOME_SUBPREMISE>(?:(?:(?:(?:(°|º|\\.|\\s|-)*(floor|flur|fl|og|obergeschoss|ug|untergeschoss|geschoss|andar|piso|º)(\\.|\\s|-)*)(?P<ADDRESS_HOME_FLOOR>(?:(\\d{0,3}\\w?))))|(?:(?P<ADDRESS_HOME_FLOOR__2>(?:(\\d{1,3}\\w?|\\w)))(?:(°|º|\\.|\\s|-)*(floor|flur|fl|og|obergeschoss|ug|untergeschoss|geschoss|andar|piso|º)(\\.|\\s|-)*)))(?:(?:^|[,\\s]+)(?:(?:(?:(apt|apartment|wohnung|apto|-)(\\.|\\s|-)*)(?P<ADDRESS_HOME_APT_NUM>(?:(\\d{0,3}\\w?))))|(?:(-\\s*)?(?P<ADDRESS_HOME_APT_NUM__2>(?:(\\d{1,3}\\w?|\\w)))(?:(\\.|\\s|-)*(ª)))?))?|(?:(?:(?:(apt|apartment|wohnung|apto|-)(\\.|\\s|-)*)(?P<ADDRESS_HOME_APT_NUM__3>(?:(\\d{0,3}\\w?))))|(?:(-\\s*)?(?P<ADDRESS_HOME_APT_NUM__4>(?:(\\d{1,3}\\w?|\\w)))(?:(\\.|\\s|-)*(ª)))?))))?))"; // nocheck
 
 
 // Section for singular decomposition(s).
-constexpr Decomposition kDecompositionList[] = {
+inline constexpr Decomposition kDecompositionList[] = {
     Decomposition(kRegularExpression_26, true, true),
     Decomposition(kRegularExpression_29, true, true),
     Decomposition(kRegularExpression_27, true, true),
@@ -114,7 +114,7 @@
 };
 
 // Section for singular extract part(s).
-constexpr ExtractPart kExtractPartList[]{
+inline constexpr ExtractPart kExtractPartList[]{
     ExtractPart("", kRegularExpression_38),
     ExtractPart("", kRegularExpression_39),
     ExtractPart("", kRegularExpression_40),
@@ -128,52 +128,52 @@
 };
 
 // Section for decomposition cascades and their alternatives.
-constexpr AutofillParsingProcess const* kDecompositionCascade_0_Alternatives[]{ &kDecompositionList[0], &kDecompositionList[1], &kDecompositionList[2], &kDecompositionList[3]};
-constexpr DecompositionCascade kDecompositionCascade_0 = DecompositionCascade(kRegularExpression_14, kDecompositionCascade_0_Alternatives);
-constexpr AutofillParsingProcess const* kDecompositionCascade_1_Alternatives[]{ &kDecompositionList[4]};
-constexpr DecompositionCascade kDecompositionCascade_1 = DecompositionCascade(kRegularExpression_13, kDecompositionCascade_1_Alternatives);
-constexpr AutofillParsingProcess const* kDecompositionCascade_2_Alternatives[]{ &kDecompositionList[5], &kDecompositionList[6], &kDecompositionList[7]};
-constexpr DecompositionCascade kDecompositionCascade_2 = DecompositionCascade("", kDecompositionCascade_2_Alternatives);
-constexpr AutofillParsingProcess const* kDecompositionCascade_3_Alternatives[]{ &kDecompositionCascade_0, &kDecompositionCascade_1, &kDecompositionCascade_2};
-constexpr DecompositionCascade kDecompositionCascade_3 = DecompositionCascade("", kDecompositionCascade_3_Alternatives);
-constexpr AutofillParsingProcess const* kDecompositionCascade_4_Alternatives[]{ &kDecompositionList[0], &kDecompositionList[1], &kDecompositionList[2], &kDecompositionList[3]};
-constexpr DecompositionCascade kDecompositionCascade_4 = DecompositionCascade(kRegularExpression_14, kDecompositionCascade_4_Alternatives);
-constexpr AutofillParsingProcess const* kDecompositionCascade_5_Alternatives[]{ &kDecompositionList[10]};
-constexpr DecompositionCascade kDecompositionCascade_5 = DecompositionCascade(kRegularExpression_13, kDecompositionCascade_5_Alternatives);
-constexpr AutofillParsingProcess const* kDecompositionCascade_6_Alternatives[]{ &kDecompositionList[5], &kDecompositionList[11], &kDecompositionList[12]};
-constexpr DecompositionCascade kDecompositionCascade_6 = DecompositionCascade("", kDecompositionCascade_6_Alternatives);
-constexpr AutofillParsingProcess const* kDecompositionCascade_7_Alternatives[]{ &kDecompositionCascade_4, &kDecompositionCascade_5, &kDecompositionCascade_6};
-constexpr DecompositionCascade kDecompositionCascade_7 = DecompositionCascade("", kDecompositionCascade_7_Alternatives);
-constexpr AutofillParsingProcess const* kDecompositionCascade_8_Alternatives[]{ &kDecompositionList[0], &kDecompositionList[1], &kDecompositionList[2], &kDecompositionList[3]};
-constexpr DecompositionCascade kDecompositionCascade_8 = DecompositionCascade(kRegularExpression_14, kDecompositionCascade_8_Alternatives);
-constexpr AutofillParsingProcess const* kDecompositionCascade_9_Alternatives[]{ &kDecompositionList[10]};
-constexpr DecompositionCascade kDecompositionCascade_9 = DecompositionCascade(kRegularExpression_13, kDecompositionCascade_9_Alternatives);
-constexpr AutofillParsingProcess const* kDecompositionCascade_10_Alternatives[]{ &kDecompositionList[5], &kDecompositionList[6], &kDecompositionList[7]};
-constexpr DecompositionCascade kDecompositionCascade_10 = DecompositionCascade("", kDecompositionCascade_10_Alternatives);
-constexpr AutofillParsingProcess const* kDecompositionCascade_11_Alternatives[]{ &kDecompositionCascade_8, &kDecompositionCascade_9, &kDecompositionCascade_10};
-constexpr DecompositionCascade kDecompositionCascade_11 = DecompositionCascade("", kDecompositionCascade_11_Alternatives);
+inline constexpr AutofillParsingProcess const* kDecompositionCascade_0_Alternatives[]{ &kDecompositionList[0], &kDecompositionList[1], &kDecompositionList[2], &kDecompositionList[3]};
+inline constexpr DecompositionCascade kDecompositionCascade_0 = DecompositionCascade(kRegularExpression_14, kDecompositionCascade_0_Alternatives);
+inline constexpr AutofillParsingProcess const* kDecompositionCascade_1_Alternatives[]{ &kDecompositionList[4]};
+inline constexpr DecompositionCascade kDecompositionCascade_1 = DecompositionCascade(kRegularExpression_13, kDecompositionCascade_1_Alternatives);
+inline constexpr AutofillParsingProcess const* kDecompositionCascade_2_Alternatives[]{ &kDecompositionList[5], &kDecompositionList[6], &kDecompositionList[7]};
+inline constexpr DecompositionCascade kDecompositionCascade_2 = DecompositionCascade("", kDecompositionCascade_2_Alternatives);
+inline constexpr AutofillParsingProcess const* kDecompositionCascade_3_Alternatives[]{ &kDecompositionCascade_0, &kDecompositionCascade_1, &kDecompositionCascade_2};
+inline constexpr DecompositionCascade kDecompositionCascade_3 = DecompositionCascade("", kDecompositionCascade_3_Alternatives);
+inline constexpr AutofillParsingProcess const* kDecompositionCascade_4_Alternatives[]{ &kDecompositionList[0], &kDecompositionList[1], &kDecompositionList[2], &kDecompositionList[3]};
+inline constexpr DecompositionCascade kDecompositionCascade_4 = DecompositionCascade(kRegularExpression_14, kDecompositionCascade_4_Alternatives);
+inline constexpr AutofillParsingProcess const* kDecompositionCascade_5_Alternatives[]{ &kDecompositionList[10]};
+inline constexpr DecompositionCascade kDecompositionCascade_5 = DecompositionCascade(kRegularExpression_13, kDecompositionCascade_5_Alternatives);
+inline constexpr AutofillParsingProcess const* kDecompositionCascade_6_Alternatives[]{ &kDecompositionList[5], &kDecompositionList[11], &kDecompositionList[12]};
+inline constexpr DecompositionCascade kDecompositionCascade_6 = DecompositionCascade("", kDecompositionCascade_6_Alternatives);
+inline constexpr AutofillParsingProcess const* kDecompositionCascade_7_Alternatives[]{ &kDecompositionCascade_4, &kDecompositionCascade_5, &kDecompositionCascade_6};
+inline constexpr DecompositionCascade kDecompositionCascade_7 = DecompositionCascade("", kDecompositionCascade_7_Alternatives);
+inline constexpr AutofillParsingProcess const* kDecompositionCascade_8_Alternatives[]{ &kDecompositionList[0], &kDecompositionList[1], &kDecompositionList[2], &kDecompositionList[3]};
+inline constexpr DecompositionCascade kDecompositionCascade_8 = DecompositionCascade(kRegularExpression_14, kDecompositionCascade_8_Alternatives);
+inline constexpr AutofillParsingProcess const* kDecompositionCascade_9_Alternatives[]{ &kDecompositionList[10]};
+inline constexpr DecompositionCascade kDecompositionCascade_9 = DecompositionCascade(kRegularExpression_13, kDecompositionCascade_9_Alternatives);
+inline constexpr AutofillParsingProcess const* kDecompositionCascade_10_Alternatives[]{ &kDecompositionList[5], &kDecompositionList[6], &kDecompositionList[7]};
+inline constexpr DecompositionCascade kDecompositionCascade_10 = DecompositionCascade("", kDecompositionCascade_10_Alternatives);
+inline constexpr AutofillParsingProcess const* kDecompositionCascade_11_Alternatives[]{ &kDecompositionCascade_8, &kDecompositionCascade_9, &kDecompositionCascade_10};
+inline constexpr DecompositionCascade kDecompositionCascade_11 = DecompositionCascade("", kDecompositionCascade_11_Alternatives);
 
 // Section for extract parts and their pieces.
-constexpr ExtractPart const* kExtractParts_0_Pieces[]{&kExtractPartList[0],&kExtractPartList[1],&kExtractPartList[2]};
-constexpr ExtractParts kExtractParts_0 = ExtractParts("", kExtractParts_0_Pieces);
-constexpr ExtractPart const* kExtractParts_1_Pieces[]{&kExtractPartList[0],&kExtractPartList[1],&kExtractPartList[2]};
-constexpr ExtractParts kExtractParts_1 = ExtractParts("", kExtractParts_1_Pieces);
-constexpr ExtractPart const* kExtractParts_2_Pieces[]{&kExtractPartList[0],&kExtractPartList[1],&kExtractPartList[2],&kExtractPartList[3]};
-constexpr ExtractParts kExtractParts_2 = ExtractParts("", kExtractParts_2_Pieces);
-constexpr ExtractPart const* kExtractParts_3_Pieces[]{&kExtractPartList[4],&kExtractPartList[0],&kExtractPartList[1],&kExtractPartList[2],&kExtractPartList[3]};
-constexpr ExtractParts kExtractParts_3 = ExtractParts("", kExtractParts_3_Pieces);
-constexpr ExtractPart const* kExtractParts_4_Pieces[]{&kExtractPartList[5],&kExtractPartList[6]};
-constexpr ExtractParts kExtractParts_4 = ExtractParts("", kExtractParts_4_Pieces);
-constexpr ExtractPart const* kExtractParts_5_Pieces[]{&kExtractPartList[7],&kExtractPartList[8]};
-constexpr ExtractParts kExtractParts_5 = ExtractParts("", kExtractParts_5_Pieces);
-constexpr ExtractPart const* kExtractParts_6_Pieces[]{&kExtractPartList[7],&kExtractPartList[8]};
-constexpr ExtractParts kExtractParts_6 = ExtractParts("", kExtractParts_6_Pieces);
-constexpr ExtractPart const* kExtractParts_7_Pieces[]{&kExtractPartList[9],&kExtractPartList[5],&kExtractPartList[6],&kExtractPartList[7],&kExtractPartList[8]};
-constexpr ExtractParts kExtractParts_7 = ExtractParts("", kExtractParts_7_Pieces);
+inline constexpr ExtractPart const* kExtractParts_0_Pieces[]{&kExtractPartList[0],&kExtractPartList[1],&kExtractPartList[2]};
+inline constexpr ExtractParts kExtractParts_0 = ExtractParts("", kExtractParts_0_Pieces);
+inline constexpr ExtractPart const* kExtractParts_1_Pieces[]{&kExtractPartList[0],&kExtractPartList[1],&kExtractPartList[2]};
+inline constexpr ExtractParts kExtractParts_1 = ExtractParts("", kExtractParts_1_Pieces);
+inline constexpr ExtractPart const* kExtractParts_2_Pieces[]{&kExtractPartList[0],&kExtractPartList[1],&kExtractPartList[2],&kExtractPartList[3]};
+inline constexpr ExtractParts kExtractParts_2 = ExtractParts("", kExtractParts_2_Pieces);
+inline constexpr ExtractPart const* kExtractParts_3_Pieces[]{&kExtractPartList[4],&kExtractPartList[0],&kExtractPartList[1],&kExtractPartList[2],&kExtractPartList[3]};
+inline constexpr ExtractParts kExtractParts_3 = ExtractParts("", kExtractParts_3_Pieces);
+inline constexpr ExtractPart const* kExtractParts_4_Pieces[]{&kExtractPartList[5],&kExtractPartList[6]};
+inline constexpr ExtractParts kExtractParts_4 = ExtractParts("", kExtractParts_4_Pieces);
+inline constexpr ExtractPart const* kExtractParts_5_Pieces[]{&kExtractPartList[7],&kExtractPartList[8]};
+inline constexpr ExtractParts kExtractParts_5 = ExtractParts("", kExtractParts_5_Pieces);
+inline constexpr ExtractPart const* kExtractParts_6_Pieces[]{&kExtractPartList[7],&kExtractPartList[8]};
+inline constexpr ExtractParts kExtractParts_6 = ExtractParts("", kExtractParts_6_Pieces);
+inline constexpr ExtractPart const* kExtractParts_7_Pieces[]{&kExtractPartList[9],&kExtractPartList[5],&kExtractPartList[6],&kExtractPartList[7],&kExtractPartList[8]};
+inline constexpr ExtractParts kExtractParts_7 = ExtractParts("", kExtractParts_7_Pieces);
 }  // namespace
 
 // A lookup map for parsing expressions for countries and field types.
-constexpr auto kAutofillParsingRulesMap =
+inline constexpr auto kAutofillParsingRulesMap =
     base::MakeFixedFlatMap<CountryAndFieldType, const AutofillParsingProcess*>({
       {{"BR", ADDRESS_HOME_STREET_LOCATION}, &kDecompositionList[8]},
       {{"BR", ADDRESS_HOME_SUBPREMISE}, &kExtractParts_0},
@@ -193,4 +193,4 @@
 
 }  // namespace autofill::i18n_model_definition
 
-#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_AUTOFILL_I18N_PARSING_EXPRESSIONS_H_
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_AUTOFILL_I18N_PARSING_EXPRESSIONS_H_
\ No newline at end of file
diff --git a/components/autofill/core/browser/data_model/iban.cc b/components/autofill/core/browser/data_model/iban.cc
index 76295af0..8d2b42a4 100644
--- a/components/autofill/core/browser/data_model/iban.cc
+++ b/components/autofill/core/browser/data_model/iban.cc
@@ -11,6 +11,8 @@
 #include "base/uuid.h"
 #include "components/autofill/core/browser/autofill_field.h"
 #include "components/autofill/core/browser/data_model/autofill_metadata.h"
+#include "components/autofill/core/browser/metrics/payments/iban_metrics.h"
+#include "components/autofill/core/common/autofill_clock.h"
 #include "components/autofill/core/common/autofill_regexes.h"
 
 namespace autofill {
@@ -386,6 +388,12 @@
   return record_type_ == kServerIban || IsValid(value_);
 }
 
+void Iban::RecordAndLogUse() {
+  autofill_metrics::LogDaysSinceLastIbanUse(*this);
+  set_use_date(AutofillClock::Now());
+  set_use_count(use_count() + 1);
+}
+
 std::u16string Iban::GetIdentifierStringForAutofillDisplay(
     bool is_value_masked) const {
   // `value_` is expected to be empty for server-based IBANs. For local IBANs,
diff --git a/components/autofill/core/browser/data_model/iban.h b/components/autofill/core/browser/data_model/iban.h
index 05ff1710..c7c017a 100644
--- a/components/autofill/core/browser/data_model/iban.h
+++ b/components/autofill/core/browser/data_model/iban.h
@@ -125,6 +125,10 @@
   // server-based IBANs because server-based IBANs don't store the full `value`.
   bool IsValid();
 
+  // Logs the number of days since this IBAN was last used, increments its use
+  // count, and updates its last used date to today.
+  void RecordAndLogUse();
+
   // Construct an IBAN identifier from `prefix_`, `suffix_`, `length_` (and
   // `value_` if it's a local-based IBAN) by the following rules:
   // 1. Always reveal the first and the last four characters.
diff --git a/components/autofill/core/browser/field_types.h b/components/autofill/core/browser/field_types.h
index c9cf410..6d06e123 100644
--- a/components/autofill/core/browser/field_types.h
+++ b/components/autofill/core/browser/field_types.h
@@ -439,7 +439,7 @@
 
   // No new types can be added without a corresponding change to the Autofill
   // server.
-  // This enum must be kept in sync with ServerFieldType from
+  // This enum must be kept in sync with FieldType from
   // * chrome/common/extensions/api/autofill_private.idl
   // * tools/typescript/definitions/autofill_private.d.ts
   // Please update `tools/metrics/histograms/enums.xml` by executing
@@ -511,8 +511,8 @@
 FieldType HtmlFieldTypeToBestCorrespondingFieldType(HtmlFieldType field_type);
 
 // Returns |raw_value| if it corresponds to a non-deprecated enumeration
-// constant of ServerFieldType other than MAX_VALID_FIELD_TYPE. Otherwise,
-// returns |fallback_value|.
+// constant of FieldType other than MAX_VALID_FIELD_TYPE. Otherwise, returns
+// |fallback_value|.
 constexpr FieldType ToSafeFieldType(std::underlying_type_t<FieldType> raw_value,
                                     FieldType fallback_value) {
   auto IsValid = [](std::underlying_type_t<FieldType> t) {
@@ -583,10 +583,6 @@
   return fields;
 }();
 
-// TODO(crbug.com/1511368): Remove aliases.
-using ServerFieldType = FieldType;
-using ServerFieldTypeSet = FieldTypeSet;
-
 }  // namespace autofill
 
 #endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_FIELD_TYPES_H_
diff --git a/components/autofill/core/browser/filling_product.cc b/components/autofill/core/browser/filling_product.cc
index 8243b52..a8869453 100644
--- a/components/autofill/core/browser/filling_product.cc
+++ b/components/autofill/core/browser/filling_product.cc
@@ -27,7 +27,6 @@
     case PopupItemId::kScanCreditCard:
     case PopupItemId::kVirtualCreditCardEntry:
     case PopupItemId::kCreditCardFieldByFieldFilling:
-    case PopupItemId::kPaymentsEntryNotSelectable:
       return FillingProduct::kCreditCard;
     case PopupItemId::kMerchantPromoCodeEntry:
       return FillingProduct::kMerchantPromoCode;
diff --git a/components/autofill/core/browser/form_data_importer.cc b/components/autofill/core/browser/form_data_importer.cc
index 0eea923..4a55c32 100644
--- a/components/autofill/core/browser/form_data_importer.cc
+++ b/components/autofill/core/browser/form_data_importer.cc
@@ -1044,7 +1044,7 @@
     std::u16string_view user_input_view =
         base::TrimWhitespace(field.user_input, base::TRIM_ALL);
     if (!user_input_view.empty() &&
-        field.Type().GetStorableType() == ServerFieldType::CREDIT_CARD_NUMBER &&
+        field.Type().GetStorableType() == FieldType::CREDIT_CARD_NUMBER &&
         base::FeatureList::IsEnabled(
             features::kAutofillUseTypedCreditCardNumber)) {
       value_view = user_input_view;
diff --git a/components/autofill/core/browser/form_parsing/address_field.cc b/components/autofill/core/browser/form_parsing/address_field.cc
index 5f76db8..63cbbf8e 100644
--- a/components/autofill/core/browser/form_parsing/address_field.cc
+++ b/components/autofill/core/browser/form_parsing/address_field.cc
@@ -28,7 +28,7 @@
   return GetMatchPatterns(name, context.page_language, context.pattern_source);
 }
 
-base::span<const MatchPatternRef> GetMatchPatterns(ServerFieldType type,
+base::span<const MatchPatternRef> GetMatchPatterns(FieldType type,
                                                    ParsingContext& context) {
   return GetMatchPatterns(type, context.page_language, context.pattern_source);
 }
diff --git a/components/autofill/core/browser/form_parsing/credit_card_field.cc b/components/autofill/core/browser/form_parsing/credit_card_field.cc
index cb02bfa..1d0b8a8 100644
--- a/components/autofill/core/browser/form_parsing/credit_card_field.cc
+++ b/components/autofill/core/browser/form_parsing/credit_card_field.cc
@@ -38,7 +38,7 @@
   return GetMatchPatterns(name, context.page_language, context.pattern_source);
 }
 
-base::span<const MatchPatternRef> GetMatchPatterns(ServerFieldType type,
+base::span<const MatchPatternRef> GetMatchPatterns(FieldType type,
                                                    ParsingContext& context) {
   return GetMatchPatterns(type, context.page_language, context.pattern_source);
 }
diff --git a/components/autofill/core/browser/metrics/payments/iban_metrics.cc b/components/autofill/core/browser/metrics/payments/iban_metrics.cc
index 5d113be..9e4f5ca 100644
--- a/components/autofill/core/browser/metrics/payments/iban_metrics.cc
+++ b/components/autofill/core/browser/metrics/payments/iban_metrics.cc
@@ -6,6 +6,7 @@
 
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
+#include "components/autofill/core/browser/data_model/iban.h"
 #include "components/autofill/core/common/autofill_clock.h"
 
 namespace autofill::autofill_metrics {
@@ -37,6 +38,17 @@
                               num_disused_local_ibans);
 }
 
+void LogDaysSinceLastIbanUse(const Iban& iban) {
+  CHECK(iban.record_type() == Iban::RecordType::kLocalIban ||
+        iban.record_type() == Iban::RecordType::kServerIban);
+  base::UmaHistogramCounts1000(
+      base::StrCat({"Autofill.DaysSinceLastUse.StoredIban.",
+                    (iban.record_type() == Iban::RecordType::kServerIban)
+                        ? "Server"
+                        : "Local"}),
+      (AutofillClock::Now() - iban.use_date()).InDays());
+}
+
 void LogStrikesPresentWhenIbanSaved(const int num_strikes,
                                     bool is_upload_save) {
   base::UmaHistogramCounts100(
diff --git a/components/autofill/core/browser/metrics/payments/iban_metrics.h b/components/autofill/core/browser/metrics/payments/iban_metrics.h
index ea1ca56..4306ee8 100644
--- a/components/autofill/core/browser/metrics/payments/iban_metrics.h
+++ b/components/autofill/core/browser/metrics/payments/iban_metrics.h
@@ -96,6 +96,9 @@
 void LogStoredIbanMetrics(const std::vector<std::unique_ptr<Iban>>& local_ibans,
                           const base::TimeDelta& disused_data_threshold);
 
+// Logs the number of days since the given IBAN was last used.
+void LogDaysSinceLastIbanUse(const Iban& iban);
+
 // Logs the number of strikes that an IBAN had when save was accepted.
 void LogStrikesPresentWhenIbanSaved(const int num_strikes, bool is_upload_save);
 
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index b46e7cc8..8414efa 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -820,6 +820,22 @@
   }
 }
 
+void PersonalDataManager::RecordUseOfIban(Iban& iban) {
+  iban.RecordAndLogUse();
+
+  if (iban.record_type() == Iban::RecordType::kServerIban) {
+    CHECK(database_helper_->GetServerDatabase())
+        << "Recording use of server IBAN metadata without server storage.";
+    database_helper_->GetServerDatabase()->UpdateServerIbanMetadata(iban);
+  } else {
+    if (database_helper_->GetLocalDatabase()) {
+      database_helper_->GetLocalDatabase()->UpdateLocalIban(iban);
+    }
+  }
+
+  Refresh();
+}
+
 void PersonalDataManager::AddProfile(const AutofillProfile& profile) {
   if (!IsAutofillProfileEnabled() || !database_helper_->GetLocalDatabase()) {
     return;
diff --git a/components/autofill/core/browser/personal_data_manager.h b/components/autofill/core/browser/personal_data_manager.h
index 98ca6e9..1ff4a80c 100644
--- a/components/autofill/core/browser/personal_data_manager.h
+++ b/components/autofill/core/browser/personal_data_manager.h
@@ -249,6 +249,10 @@
       absl::variant<const AutofillProfile*, const CreditCard*>
           profile_or_credit_card);
 
+  // Called to indicate `iban` was used (to fill in a form). Updates the
+  // database accordingly.
+  void RecordUseOfIban(Iban& iban);
+
   // Called when the user accepts the prompt to save the credit card locally.
   // Records some metrics and attempts to save the imported card. Returns the
   // guid of the new or updated card, or the empty string if no card was saved.
diff --git a/components/autofill/core/browser/personal_data_manager_unittest.cc b/components/autofill/core/browser/personal_data_manager_unittest.cc
index e2ffb97..54d32b0 100644
--- a/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -1291,6 +1291,60 @@
   ExpectSameElements(ibans, personal_data_->GetLocalIbans());
 }
 
+TEST_F(PersonalDataManagerTest, RecordIbanUsage_LocalIban) {
+  base::HistogramTester histogram_tester;
+  // Create the test clock and set the time to a specific value.
+  TestAutofillClock test_clock;
+  test_clock.SetNow(kArbitraryTime);
+  Iban local_iban;
+  local_iban.set_value(u"FR76 3000 6000 0112 3456 7890 189");
+  EXPECT_EQ(local_iban.use_count(), 1u);
+  EXPECT_EQ(local_iban.use_date(), kArbitraryTime);
+  EXPECT_EQ(local_iban.modification_date(), kArbitraryTime);
+
+  AddLocalIban(local_iban);
+
+  // Set the current time to sometime later.
+  test_clock.SetNow(kSomeLaterTime);
+
+  // Use `local_iban`, then verify usage stats.
+  EXPECT_EQ(personal_data_->GetLocalIbans().size(), 1u);
+  personal_data_->RecordUseOfIban(local_iban);
+  PersonalDataProfileTaskWaiter(*personal_data_).Wait();
+  histogram_tester.ExpectTotalCount(
+      "Autofill.DaysSinceLastUse.StoredIban.Local", 1);
+  EXPECT_EQ(local_iban.use_count(), 2u);
+  EXPECT_EQ(local_iban.use_date(), kSomeLaterTime);
+  EXPECT_EQ(local_iban.modification_date(), kArbitraryTime);
+}
+
+TEST_F(PersonalDataManagerTest, RecordIbanUsage_ServerIban) {
+  base::HistogramTester histogram_tester;
+  // Create the test clock and set the time to a specific value.
+  TestAutofillClock test_clock;
+  test_clock.SetNow(kArbitraryTime);
+  Iban server_iban = test::GetServerIban();
+  EXPECT_EQ(server_iban.use_count(), 1u);
+  EXPECT_EQ(server_iban.use_date(), kArbitraryTime);
+  EXPECT_EQ(server_iban.modification_date(), kArbitraryTime);
+  GetServerDataTable()->SetServerIbansForTesting({server_iban});
+  personal_data_->Refresh();
+  PersonalDataProfileTaskWaiter(*personal_data_).Wait();
+
+  // Set the current time to sometime later.
+  test_clock.SetNow(kSomeLaterTime);
+
+  // Use `server_iban`, then verify usage stats.
+  EXPECT_EQ(personal_data_->GetServerIbans().size(), 1u);
+  personal_data_->RecordUseOfIban(server_iban);
+  PersonalDataProfileTaskWaiter(*personal_data_).Wait();
+  histogram_tester.ExpectTotalCount(
+      "Autofill.DaysSinceLastUse.StoredIban.Server", 1);
+  EXPECT_EQ(server_iban.use_count(), 2u);
+  EXPECT_EQ(server_iban.use_date(), kSomeLaterTime);
+  EXPECT_EQ(server_iban.modification_date(), kArbitraryTime);
+}
+
 TEST_F(PersonalDataManagerTest, AddUpdateRemoveCreditCards) {
   CreditCard credit_card0(base::Uuid::GenerateRandomV4().AsLowercaseString(),
                           test::kEmptyOrigin);
diff --git a/components/autofill/core/browser/ui/popup_item_ids.h b/components/autofill/core/browser/ui/popup_item_ids.h
index 0e426a46..298f5c2 100644
--- a/components/autofill/core/browser/ui/popup_item_ids.h
+++ b/components/autofill/core/browser/ui/popup_item_ids.h
@@ -69,7 +69,6 @@
   kVirtualCreditCardEntry,
   kCreditCardFieldByFieldFilling,
   kIbanEntry,
-  kPaymentsEntryNotSelectable,
 
   // Plus address suggestions.
   kCreateNewPlusAddress,
diff --git a/components/autofill/core/browser/ui/popup_types.h b/components/autofill/core/browser/ui/popup_types.h
index 2ccdbd99..37b503b 100644
--- a/components/autofill/core/browser/ui/popup_types.h
+++ b/components/autofill/core/browser/ui/popup_types.h
@@ -81,7 +81,11 @@
   // Sub-popup related reason, used when closing a sub-popup (e.g. by moving
   // the mouse out of the suggestion control or by the keyboard navigation).
   kExpandedSuggestionCollapsedSubPopup = 24,
-  kMaxValue = kExpandedSuggestionCollapsedSubPopup
+  // The field's value changed. Currently, this event is only used for
+  // Compose-related
+  // popups, which close in response to user edits of the focused field.
+  kFieldValueChanged = 25,
+  kMaxValue = kFieldValueChanged
 };
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/ui/suggestion.h b/components/autofill/core/browser/ui/suggestion.h
index f1c4b6a9..151aa0ee 100644
--- a/components/autofill/core/browser/ui/suggestion.h
+++ b/components/autofill/core/browser/ui/suggestion.h
@@ -228,6 +228,10 @@
   // `FieldType` used to build the suggestion's `main_text`.
   std::optional<FieldType> field_by_field_filling_type_used;
 
+  // Whether the user is able to select the suggestion by hovering on it or
+  // accept it by clicking on it.
+  bool is_selectable = true;
+
   // Denotes whether this suggestion was hidden prior to the effects caused by
   // kAutofillUseAddressRewriterInProfileSubsetComparison.
   // TODO(crbug.com/1439742): Remove when the feature launches.
diff --git a/components/autofill/core/browser/webdata/addresses/address_autofill_table.cc b/components/autofill/core/browser/webdata/addresses/address_autofill_table.cc
index 5cb16538..866106b 100644
--- a/components/autofill/core/browser/webdata/addresses/address_autofill_table.cc
+++ b/components/autofill/core/browser/webdata/addresses/address_autofill_table.cc
@@ -140,12 +140,6 @@
 constexpr std::string_view kVerificationStatus = "verification_status";
 constexpr std::string_view kObservations = "observations";
 
-// Truncates `data` to the maximum length that can be stored in a column of the
-// Autofill database. Shorter strings are left as-is.
-std::u16string Truncate(const std::u16string& data) {
-  return data.substr(0, AddressAutofillTable::kMaxDataLength);
-}
-
 void AddAutofillProfileDetailsFromStatement(sql::Statement& s,
                                             AutofillProfile* profile) {
   int index = 0;
@@ -477,9 +471,6 @@
 
 }  // namespace
 
-// static
-const size_t AddressAutofillTable::kMaxDataLength = 1024;
-
 AddressAutofillTable::AddressAutofillTable() = default;
 
 AddressAutofillTable::~AddressAutofillTable() = default;
diff --git a/components/autofill/core/browser/webdata/addresses/address_autofill_table.h b/components/autofill/core/browser/webdata/addresses/address_autofill_table.h
index f6156856..bdbc55f 100644
--- a/components/autofill/core/browser/webdata/addresses/address_autofill_table.h
+++ b/components/autofill/core/browser/webdata/addresses/address_autofill_table.h
@@ -315,11 +315,6 @@
   bool MigrateToVersion117AddProfileObservationColumn();
   bool MigrateToVersion121DropServerAddressTables();
 
-  // Max data length saved in the table, AKA the maximum length allowed for
-  // form data.
-  // Copied to components/autofill/ios/browser/resources/autofill_controller.js.
-  static const size_t kMaxDataLength;
-
  private:
   // Reads profiles from the deprecated autofill_profiles table.
   std::unique_ptr<AutofillProfile> GetAutofillProfileFromLegacyTable(
diff --git a/components/autofill/core/browser/webdata/autofill_table.cc b/components/autofill/core/browser/webdata/autofill_table.cc
index ef6f527..0a638d9 100644
--- a/components/autofill/core/browser/webdata/autofill_table.cc
+++ b/components/autofill/core/browser/webdata/autofill_table.cc
@@ -280,12 +280,6 @@
         {kBenefitId, "VARCHAR NOT NULL"},
         {kMerchantDomain, "VARCHAR NOT NULL"}};
 
-// Truncates `data` to the maximum length that can be stored in a column of the
-// Autofill database. Shorter strings are left as-is.
-std::u16string Truncate(const std::u16string& data) {
-  return data.substr(0, AutofillTable::kMaxDataLength);
-}
-
 void BindEncryptedValueToColumn(sql::Statement* s,
                                 int column_index,
                                 const std::u16string& value,
@@ -498,9 +492,6 @@
 
 PaymentInstrumentFields::~PaymentInstrumentFields() = default;
 
-// static
-const size_t AutofillTable::kMaxDataLength = 1024;
-
 AutofillTable::AutofillTable()
     : autofill_table_encryptor_(
           AutofillTableEncryptorFactory::GetInstance()->Create()) {
diff --git a/components/autofill/core/browser/webdata/autofill_table.h b/components/autofill/core/browser/webdata/autofill_table.h
index e5937f5..cf08c64 100644
--- a/components/autofill/core/browser/webdata/autofill_table.h
+++ b/components/autofill/core/browser/webdata/autofill_table.h
@@ -695,11 +695,6 @@
   bool MigrateToVersion120AddPaymentInstrumentAndBankAccountTables();
   bool MigrateToVersion123AddProductTermsUrlColumnAndAddCardBenefitsTables();
 
-  // Max data length saved in the table, AKA the maximum length allowed for
-  // form data.
-  // Copied to components/autofill/ios/browser/resources/autofill_controller.js.
-  static const size_t kMaxDataLength;
-
  private:
   bool SupportsMetadataForModelType(syncer::ModelType model_type) const;
   int GetKeyValueForModelType(syncer::ModelType model_type) const;
diff --git a/components/autofill/core/browser/webdata/autofill_table_utils.cc b/components/autofill/core/browser/webdata/autofill_table_utils.cc
index 06a3ec5..a77a89af 100644
--- a/components/autofill/core/browser/webdata/autofill_table_utils.cc
+++ b/components/autofill/core/browser/webdata/autofill_table_utils.cc
@@ -16,6 +16,10 @@
 
 namespace autofill {
 
+std::u16string Truncate(std::u16string_view data) {
+  return std::u16string(data.substr(0, kMaxDataLengthForDatabase));
+}
+
 bool CreateTable(
     sql::Database* db,
     std::string_view table_name,
diff --git a/components/autofill/core/browser/webdata/autofill_table_utils.h b/components/autofill/core/browser/webdata/autofill_table_utils.h
index 0228308d..b424f0a 100644
--- a/components/autofill/core/browser/webdata/autofill_table_utils.h
+++ b/components/autofill/core/browser/webdata/autofill_table_utils.h
@@ -17,6 +17,13 @@
 
 namespace autofill {
 
+// Max length of values stored in address and payments related tables. This
+// limit is not enforced for autocomplete values.
+inline constexpr size_t kMaxDataLengthForDatabase = 1024;
+
+// Truncates `data` to `kMaxDataLengthForDatabase`.
+std::u16string Truncate(std::u16string_view data);
+
 // Helper functions to construct SQL statements from string constants.
 // - Functions with names corresponding to SQL keywords execute the statement
 //   directly and return if it was successful.
diff --git a/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc b/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
index 13606e3d..0047f51 100644
--- a/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
+++ b/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
@@ -15,6 +15,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/types/cxx23_to_underlying.h"
+#include "components/autofill/core/browser/data_model/autofill_metadata.h"
 #include "components/autofill/core/browser/data_model/autofill_offer_data.h"
 #include "components/autofill/core/browser/data_model/autofill_wallet_usage_data.h"
 #include "components/autofill/core/browser/data_model/credit_card.h"
@@ -109,7 +110,9 @@
   kUpdateCreditCardCvc_Failure = 271,
   kClearLocalCvcs_Success = 272,
   kClearLocalCvcs_Failure = 273,
-  kMaxValue = kClearLocalCvcs_Failure,
+  kUpdateServerIbanMetadata_Success = 274,
+  kUpdateServerIbanMetadata_Failure = 275,
+  kMaxValue = kUpdateServerIbanMetadata_Failure,
 };
 
 // Reports the success or failure of various operations on the database via UMA.
@@ -706,6 +709,26 @@
   return WebDatabase::COMMIT_NEEDED;
 }
 
+WebDatabase::State AutofillWebDataBackendImpl::UpdateServerIbanMetadata(
+    const Iban& iban,
+    WebDatabase* db) {
+  CHECK(owning_task_runner()->RunsTasksInCurrentSequence());
+  CHECK_EQ(Iban::RecordType::kServerIban, iban.record_type());
+  if (!AutofillTable::FromWebDatabase(db)->AddOrUpdateServerIbanMetadata(
+          iban.GetMetadata())) {
+    ReportResult(Result::kUpdateServerIbanMetadata_Failure);
+    return WebDatabase::COMMIT_NOT_NEEDED;
+  }
+
+  for (auto& db_observer : db_observer_list_) {
+    db_observer.IbanChanged(
+        IbanChange(IbanChange::UPDATE, iban.instrument_id(), iban));
+  }
+
+  ReportResult(Result::kUpdateServerIbanMetadata_Success);
+  return WebDatabase::COMMIT_NEEDED;
+}
+
 WebDatabase::State AutofillWebDataBackendImpl::AddServerCvc(
     int64_t instrument_id,
     const std::u16string& cvc,
diff --git a/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h b/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h
index e50041f..b695fba5 100644
--- a/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h
+++ b/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h
@@ -183,6 +183,10 @@
   // Removes an IBAN from the web database.
   WebDatabase::State RemoveLocalIban(const std::string& guid, WebDatabase* db);
 
+  // Updates the given `iban`'s metadata in the web database.
+  WebDatabase::State UpdateServerIbanMetadata(const Iban& iban,
+                                              WebDatabase* db);
+
   // Server credit cards can be masked (only last 4 digits stored) or unmasked
   // (all data stored). These toggle between the two states.
   WebDatabase::State UnmaskServerCreditCard(const CreditCard& card,
diff --git a/components/autofill/core/browser/webdata/autofill_webdata_service.cc b/components/autofill/core/browser/webdata/autofill_webdata_service.cc
index 45eef46..5497b584 100644
--- a/components/autofill/core/browser/webdata/autofill_webdata_service.cc
+++ b/components/autofill/core/browser/webdata/autofill_webdata_service.cc
@@ -228,6 +228,13 @@
                                 autofill_backend_, guid));
 }
 
+void AutofillWebDataService::UpdateServerIbanMetadata(const Iban& iban) {
+  wdbs_->ScheduleDBTask(
+      FROM_HERE,
+      base::BindOnce(&AutofillWebDataBackendImpl::UpdateServerIbanMetadata,
+                     autofill_backend_, iban));
+}
+
 void AutofillWebDataService::AddServerCvc(int64_t instrument_id,
                                           const std::u16string& cvc) {
   wdbs_->ScheduleDBTask(
diff --git a/components/autofill/core/browser/webdata/autofill_webdata_service.h b/components/autofill/core/browser/webdata/autofill_webdata_service.h
index 1b12c98..c4d28c83 100644
--- a/components/autofill/core/browser/webdata/autofill_webdata_service.h
+++ b/components/autofill/core/browser/webdata/autofill_webdata_service.h
@@ -123,6 +123,9 @@
   // `guid` is the identifier of the IBAN to remove.
   void RemoveLocalIban(const std::string& guid);
 
+  // Updates the metadata for a server IBAN.
+  void UpdateServerIbanMetadata(const Iban& iban);
+
   // Schedules a task to add credit card to the web database.
   void AddCreditCard(const CreditCard& credit_card);
 
diff --git a/components/autofill/ios/form_util/BUILD.gn b/components/autofill/ios/form_util/BUILD.gn
index 7c178d8..8fff46f4 100644
--- a/components/autofill/ios/form_util/BUILD.gn
+++ b/components/autofill/ios/form_util/BUILD.gn
@@ -107,18 +107,18 @@
 }
 
 compile_ts("fill_js_dependencies") {
-  allow_js = true
   sources = [
     "resources/create_fill_namespace.ts",
     "resources/fill_constants.ts",
     "resources/fill_element_inference.ts",
     "resources/fill_element_inference_util.ts",
-    "resources/fill_util.js",
+    "resources/fill_util.ts",
   ]
 
   deps = [
     ":autofill_form_features_ts",
     "//ios/web/public/js_messaging:gcrweb",
+    "//ios/web/public/js_messaging:util_scripts",
   ]
 }
 
diff --git a/components/autofill/ios/form_util/resources/fill_constants.ts b/components/autofill/ios/form_util/resources/fill_constants.ts
index 8c30b40..05c4780c 100644
--- a/components/autofill/ios/form_util/resources/fill_constants.ts
+++ b/components/autofill/ios/form_util/resources/fill_constants.ts
@@ -4,6 +4,9 @@
 
 import {gCrWeb} from '//ios/web/public/js_messaging/resources/gcrweb.js';
 
+declare type FormControlElement =
+    HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;
+
 /**
  * The maximum length allowed for form data.
  *
@@ -80,6 +83,7 @@
 const ID_SYMBOL = window.Symbol.for('__gChrome~uniqueID');
 
 export {
+  FormControlElement,
   MAX_DATA_LENGTH,
   MAX_STRING_LENGTH,
   MAX_EXTRACTABLE_FIELDS,
diff --git a/components/autofill/ios/form_util/resources/fill_element_inference.ts b/components/autofill/ios/form_util/resources/fill_element_inference.ts
index b3c665ef..b6d6ba6 100644
--- a/components/autofill/ios/form_util/resources/fill_element_inference.ts
+++ b/components/autofill/ios/form_util/resources/fill_element_inference.ts
@@ -2,11 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {gCrWeb} from '//ios/web/public/js_messaging/resources/gcrweb.js';
+import {FormControlElement} from '//components/autofill/ios/form_util/resources/fill_constants.js';
 import * as inferenceUtil from '//components/autofill/ios/form_util/resources/fill_element_inference_util.js';
-
-declare type FormControlElement
-    = HTMLInputElement|HTMLTextAreaElement|HTMLSelectElement;
+import {gCrWeb} from '//ios/web/public/js_messaging/resources/gcrweb.js';
 
 /**
  * Shared function for InferLabelFromPrevious() and InferLabelFromNext().
diff --git a/components/autofill/ios/form_util/resources/fill_util.js b/components/autofill/ios/form_util/resources/fill_util.ts
similarity index 64%
rename from components/autofill/ios/form_util/resources/fill_util.js
rename to components/autofill/ios/form_util/resources/fill_util.ts
index 47db1c85..ce6181d 100644
--- a/components/autofill/ios/form_util/resources/fill_util.js
+++ b/components/autofill/ios/form_util/resources/fill_util.ts
@@ -4,6 +4,31 @@
 
 import * as fillConstants from '//components/autofill/ios/form_util/resources/fill_constants.js';
 import {findChildText} from '//components/autofill/ios/form_util/resources/fill_element_inference_util.js';
+import {gCrWeb} from '//ios/web/public/js_messaging/resources/gcrweb.js';
+import {trim} from '//ios/web/public/js_messaging/resources/utils.js';
+
+declare global {
+    // Defines an additional property, `angular`, on the Window object.
+    // The code below assumes that this property exists within the object.
+    interface Window {
+        angular: any;
+    }
+
+    // Extends the Document object to add the ability to access its
+    // properties via the [] notation and defines a property that is
+    // assumed to exist within the object.
+    interface Document {
+      [key: symbol]: number;
+
+      __gCrWebURLNormalizer: HTMLAnchorElement;
+    }
+}
+
+// Extends the Element to add the ability to access its properties
+// via the [] notation.
+declare interface IndexableElement extends Element {
+    [key: symbol]: number;
+}
 
 /**
  * Maps elements using their unique ID
@@ -11,14 +36,15 @@
 const elementMap = new Map();
 
 /**
- * Acquires the specified DOM |attribute| from the DOM |element| and returns
+ * Acquires the specified DOM `attribute` from the DOM `element` and returns
  * its lower-case value, or null if not present.
  *
- * @param {Element} element A DOM element.
- * @param {string} attribute An attribute name.
- * @return {?string} Lowercase value of DOM element or null if not present.
+ * @param element A DOM element.
+ * @param attribute An attribute name.
+ * @return Lowercase value of DOM element or null if not present.
  */
-function getLowerCaseAttribute(element, attribute) {
+function getLowerCaseAttribute(
+    element: Element | null, attribute: string): string | null {
   if (!element) {
     return null;
   }
@@ -37,10 +63,10 @@
  * in chromium/src/third_party/WebKit/Source/WebKit/chromium/src/
  * WebFormElement.cpp.
  *
- * @param {Element} element An element to check if it can be autocompleted.
- * @return {boolean} true if element can be autocompleted.
+ * @param element An element to check if it can be autocompleted.
+ * @return true if element can be autocompleted.
  */
-function autoComplete(element) {
+function autoComplete(element: fillConstants.FormControlElement|null): boolean {
   if (!element) {
     return false;
   }
@@ -56,17 +82,19 @@
 /**
  * Returns true if an element should suggest autocomplete dropdown.
  *
- * @param {Element} element An element to check if it can be autocompleted.
- * @return {boolean} true if autocomplete dropdown should be suggested.
+ * @param element An element to check if it can be autocompleted.
+ * @return true if autocomplete dropdown should be suggested.
  */
-__gCrWeb.fill.shouldAutocomplete = function(element) {
+gCrWeb.fill.shouldAutocomplete = function(
+    element: fillConstants.FormControlElement|null): boolean {
   if (!autoComplete(element)) {
     return false;
   }
-  if (getLowerCaseAttribute(element, 'autocomplete') === 'one-time-code') {
+  if (getLowerCaseAttribute(element!, 'autocomplete') === 'one-time-code') {
     return false;
   }
-  if (getLowerCaseAttribute(element.form, 'autocomplete') === 'one-time-code') {
+  if (getLowerCaseAttribute(
+    element!.form, 'autocomplete') === 'one-time-code') {
     return false;
   }
   return true;
@@ -82,10 +110,11 @@
  * https://docs.angularjs.org/api/auto/service/$injector
  * https://docs.angularjs.org/api/ng/service/$parse
  *
- * @param {string} value The value the input element will be set.
- * @param {Element} input The input element of which the value is set.
+ * @param value The value the input element will be set.
+ * @param input The input element of which the value is set.
  */
-function setInputElementAngularValue(value, input) {
+function setInputElementAngularValue(
+    value: string, input: Element | null): void {
   if (!input || !window['angular']) {
     return;
   }
@@ -102,7 +131,7 @@
   }
   angularElement.injector().invoke([
     '$parse',
-    function(parse) {
+    function(parse: Function) {
       const setter = parse(angularModel);
       setter.assign(angularScope, value);
     },
@@ -111,7 +140,7 @@
 
 /**
  * Sets the value of an input, dispatches the events on the changed element and
- * call |callback| if it is defined.
+ * call `callback` if it is defined.
  *
  * It is based on the logic in
  *
@@ -124,22 +153,23 @@
  *    void setChecked(bool nowChecked, TextFieldEventBehavior eventBehavior)
  * in chromium/src/third_party/WebKit/Source/core/html/HTMLInputElement.cpp.
  *
- * @param {string} value The value the input element will be set.
- * @param {Element} input The input element of which the value is set.
- * @param {function()=} callback Callback function called after the input
+ * @param value The value the input element will be set.
+ * @param input The input element of which the value is set.
+ * @param callback Callback function called after the input
  *     element's value is changed.
- * @return {boolean} Whether the value has been set successfully.
+ * @return Whether the value has been set successfully.
  */
-__gCrWeb.fill.setInputElementValue = function(
-    value, input, callback = undefined) {
+gCrWeb.fill.setInputElementValue = function(
+    value: string, input: HTMLInputElement|null,
+    callback: Function|undefined = undefined): boolean {
   if (!input) {
     return false;
   }
 
   const activeElement = document.activeElement;
   if (input !== activeElement) {
-    createAndDispatchHTMLEvent(activeElement, value, 'blur', true, false);
-    createAndDispatchHTMLEvent(input, value, 'focus', true, false);
+    createAndDispatchHTMLEvent(activeElement, 'blur', true, false);
+    createAndDispatchHTMLEvent(input, 'focus', true, false);
   }
 
   const filled = setInputElementValue(value, input);
@@ -148,20 +178,26 @@
   }
 
   if (input !== activeElement) {
-    createAndDispatchHTMLEvent(input, value, 'blur', true, false);
-    createAndDispatchHTMLEvent(activeElement, value, 'focus', true, false);
+    createAndDispatchHTMLEvent(input, 'blur', true, false);
+    createAndDispatchHTMLEvent(activeElement, 'focus', true, false);
   }
   return filled;
 };
 
+declare interface PropertyDescriptor {
+    get(): string;
+    set?(): void;
+    configurable: boolean;
+}
+
 /**
  * Internal function to set the element value.
  *
- * @param {string} value The value the input element will be set.
- * @param {Element} input The input element of which the value is set.
- * @return {boolean} Whether the value has been set successfully.
+ * @param value The value the input element will be set.
+ * @param input The input element of which the value is set.
+ * @return Whether the value has been set successfully.
  */
-function setInputElementValue(value, input) {
+function setInputElementValue(value: string, input: HTMLInputElement): boolean {
   const propertyName = (input.type === 'checkbox' || input.type === 'radio') ?
       'checked' :
       'value';
@@ -194,14 +230,14 @@
   // The setter simply forwards the set to the older property descriptor.
   // Once the setter has been called, just forward get and set calls.
 
-  const oldPropertyDescriptor = /** @type {!Object} */ (
-      Object.getOwnPropertyDescriptor(input, propertyName));
+  const oldPropertyDescriptor =
+      Object.getOwnPropertyDescriptor(input, propertyName);
   const overrideProperty =
       oldPropertyDescriptor && oldPropertyDescriptor.configurable;
   let setterCalled = false;
 
   if (overrideProperty) {
-    const newProperty = {
+    const newProperty: PropertyDescriptor = {
       get() {
         if (setterCalled && oldPropertyDescriptor.get) {
           return oldPropertyDescriptor.get.call(input);
@@ -213,15 +249,15 @@
       configurable: true,
     };
     if (oldPropertyDescriptor.set) {
-      newProperty.set = function(e) {
+      newProperty.set = function() {
         setterCalled = true;
-        oldPropertyDescriptor.set.call(input, value);
+        oldPropertyDescriptor.set!.call(input, value);
       };
     }
     Object.defineProperty(input, propertyName, newProperty);
   } else {
     setterCalled = true;
-    input[propertyName] = value;
+    (input[propertyName] as boolean|string) = value;
   }
 
   if (window['angular']) {
@@ -229,7 +265,7 @@
     // sending events.
     setInputElementAngularValue(value, input);
   }
-  notifyElementValueChanged(input, value);
+  notifyElementValueChanged(input);
 
   if (overrideProperty) {
     Object.defineProperty(input, propertyName, oldPropertyDescriptor);
@@ -238,7 +274,7 @@
       // ignored the input event) or not (the event did not conform to what
       // framework expected). The whole function will likely fail, but try to
       // set the value directly as a last try.
-      input[propertyName] = value;
+      (input[propertyName] as boolean|string) = value;
     }
   }
   return true;
@@ -252,12 +288,13 @@
  *
  * in chromium/src/third_party/WebKit/Source/core/html/InputType.h
  *
- * @param {string} proposedValue The proposed value.
- * @param {Element} element The element for which the proposedValue is to be
+ * @param proposedValue The proposed value.
+ * @param element The element for which the proposedValue is to be
  *     sanitized.
- * @return {string} The sanitized value.
+ * @return The sanitized value.
  */
-function sanitizeValueForInputElement(proposedValue, element) {
+function sanitizeValueForInputElement(
+    proposedValue: string|null, element: Element): string {
   if (!proposedValue) {
     return '';
   }
@@ -271,8 +308,9 @@
   // chromium/src/third_party/WebKit/Source/core/html/). Currently only
   // TextFieldInputType is relevant and sanitizeValue() for other types of
   // input elements has not been implemented.
-  if (__gCrWeb.common.isTextField(element)) {
-    return sanitizeValueForTextFieldInputType(proposedValue, element);
+  if (gCrWeb.common.isTextField(element)) {
+    return sanitizeValueForTextFieldInputType(
+        proposedValue, element as HTMLInputElement);
   }
   return proposedValue;
 }
@@ -280,16 +318,17 @@
 /**
  * Returns a sanitized value for a text field.
  *
- * The logic is based on |String sanitizeValue(const String&)|
+ * The logic is based on `String sanitizeValue(const String&)`
  * in chromium/src/third_party/WebKit/Source/core/html/TextFieldInputType.h
  * Note this method is overridden in EmailInputType and NumberInputType.
  *
- * @param {string} proposedValue The proposed value.
- * @param {Element} element The element for which the proposedValue is to be
+ * @param proposedValue The proposed value.
+ * @param element The element for which the proposedValue is to be
  *     sanitized.
- * @return {string} The sanitized value.
+ * @return The sanitized value.
  */
-function sanitizeValueForTextFieldInputType(proposedValue, element) {
+function sanitizeValueForTextFieldInputType(
+    proposedValue: string, element: HTMLInputElement): string {
   const textFieldElementType = element.type;
   if (textFieldElementType === 'email') {
     return sanitizeValueForEmailInputType(proposedValue, element);
@@ -307,7 +346,7 @@
   let newLength = valueWithLineBreakRemoved.length;
   // This logic is from method String limitLength() in TextFieldInputType.h
   for (let i = 0; i < newLength; ++i) {
-    const current = valueWithLineBreakRemoved[i];
+    const current = valueWithLineBreakRemoved[i]!;
     if (current < ' ' && current !== '\t') {
       newLength = i;
       break;
@@ -325,20 +364,21 @@
  *
  * in chromium/src/third_party/WebKit/Source/core/html/EmailInputType.cpp
  *
- * @param {string} proposedValue The proposed value.
- * @param {Element} element The element for which the proposedValue is to be
+ * @param proposedValue The proposed value.
+ * @param element The element for which the proposedValue is to be
  *     sanitized.
- * @return {string} The sanitized value.
+ * @return The sanitized value.
  */
-function sanitizeValueForEmailInputType(proposedValue, element) {
+function sanitizeValueForEmailInputType(
+    proposedValue: string, element: HTMLInputElement): string {
   const valueWithLineBreakRemoved = proposedValue.replace(/(\r\n|\n\r)/gm, '');
 
   if (!element.multiple) {
-    return __gCrWeb.common.trim(proposedValue);
+    return trim(proposedValue);
   }
   const addresses = valueWithLineBreakRemoved.split(',');
   for (let i = 0; i < addresses.length; ++i) {
-    addresses[i] = __gCrWeb.common.trim(addresses[i]);
+    addresses[i] = trim(addresses[i]!);
   }
   return addresses.join(',');
 }
@@ -357,10 +397,10 @@
  * Note in this implementation method Number() is used in the place of method
  * parseToDoubleForNumberType() called in NumberInputType.cpp.
  *
- * @param {string} proposedValue The proposed value.
- * @return {string} The sanitized value.
+ * @param proposedValue The proposed value.
+ * @return The sanitized value.
  */
-function sanitizeValueForNumberInputType(proposedValue) {
+function sanitizeValueForNumberInputType(proposedValue: string): string {
   const sanitizedValue = Number(proposedValue);
   if (isNaN(sanitizedValue)) {
     return '';
@@ -377,12 +417,12 @@
  *
  * @param {Element} element The element that changed.
  */
-function notifyElementValueChanged(element, value) {
-  createAndDispatchHTMLEvent(element, value, 'keydown', true, false);
-  createAndDispatchHTMLEvent(element, value, 'keypress', true, false);
-  createAndDispatchHTMLEvent(element, value, 'input', true, false);
-  createAndDispatchHTMLEvent(element, value, 'keyup', true, false);
-  createAndDispatchHTMLEvent(element, value, 'change', true, false);
+function notifyElementValueChanged(element: Element): void {
+  createAndDispatchHTMLEvent(element, 'keydown', true, false);
+  createAndDispatchHTMLEvent(element, 'keypress', true, false);
+  createAndDispatchHTMLEvent(element, 'input', true, false);
+  createAndDispatchHTMLEvent(element, 'keyup', true, false);
+  createAndDispatchHTMLEvent(element, 'change', true, false);
 }
 
 /**
@@ -395,23 +435,18 @@
  * @param {boolean} cancelable A boolean indicating whether the event can be
  *     canceled.
  */
-function createAndDispatchHTMLEvent(element, value, type, bubbles, cancelable) {
+function createAndDispatchHTMLEvent(
+    element: Element | null, type: string, bubbles: boolean,
+    cancelable: boolean): void {
   const event =
-      new Event(type, {bubbles: bubbles, cancelable: cancelable, data: value});
-  if (type === 'input') {
-    event.inputType = 'insertText';
-  }
-  element.dispatchEvent(event);
+      new Event(type, {bubbles: bubbles, cancelable: cancelable});
+  element?.dispatchEvent(event);
 }
 
 /**
  * Converts a relative URL into an absolute URL.
- *
- * @param {Object} doc Document.
- * @param {string} relativeURL Relative URL.
- * @return {string} Absolute URL.
  */
-function absoluteURL(doc, relativeURL) {
+function absoluteURL(doc: Document, relativeURL: string): string {
   // In the case of data: URL-based pages, relativeURL === absoluteURL.
   if (doc.location.protocol === 'data:') {
     return doc.location.href;
@@ -429,20 +464,25 @@
 }
 
 /**
- * Returns a canonical action for |formElement|. It works the same as upstream
+ * Returns a canonical action for `formElement`. It works the same as upstream
  * function GetCanonicalActionForForm.
- * @param {HTMLFormElement} formElement
- * @return {string} Canonical action.
+ * @return Canonical action.
  */
-__gCrWeb.fill.getCanonicalActionForForm = function(formElement) {
+gCrWeb.fill.getCanonicalActionForForm = function(
+    formElement: HTMLFormElement): string {
   const rawAction = formElement.getAttribute('action') || '';
   const absoluteUrl = absoluteURL(formElement.ownerDocument, rawAction);
-  return __gCrWeb.common.removeQueryAndReferenceFromURL(absoluteUrl);
+  return gCrWeb.common.removeQueryAndReferenceFromURL(absoluteUrl);
 };
 
+declare interface OptionFieldStrings {
+    option_values: string[] & {toJSON?: string|null};
+    option_contents: string[] & {toJSON?: string|null};
+}
+
 /**
- * Fills |field| data with the values of the <option> elements present in
- * |selectElement|.
+ * Fills `field` data with the values of the <option> elements present in
+ * `selectElement`.
  *
  * It is based on the logic in
  *     void GetOptionStringsFromElement(const WebSelectElement& select_element,
@@ -450,24 +490,25 @@
  *                                      std::vector<string16>* option_contents)
  * in chromium/src/components/autofill/content/renderer/form_autofill_util.cc.
  *
- * @param {Element} selectElement A select element from which option data are
+ * @param selectElement A select element from which option data are
  *     extracted.
- * @param {Object} field A field that will contain the extracted option
+ * @param field A field that will contain the extracted option
  *     information.
  */
-__gCrWeb.fill.getOptionStringsFromElement = function(selectElement, field) {
-  field['option_values'] = [];
+gCrWeb.fill.getOptionStringsFromElement = function(
+    selectElement: HTMLSelectElement, field: OptionFieldStrings): void {
+  field.option_values = [];
   // Protect against custom implementation of Array.toJSON in host pages.
-  field['option_values'].toJSON = null;
-  field['option_contents'] = [];
-  field['option_contents'].toJSON = null;
+  field.option_values.toJSON = null;
+  field.option_contents = [];
+  field.option_contents.toJSON = null;
   const options = selectElement.options;
   for (let i = 0; i < options.length; ++i) {
-    const option = options[i];
-    field['option_values'].push(
-        option['value'].substring(0, fillConstants.MAX_STRING_LENGTH));
-    field['option_contents'].push(
-        option['text'].substring(0, fillConstants.MAX_STRING_LENGTH));
+    const option = options[i]!;
+    field.option_values.push(
+        option.value.substring(0, fillConstants.MAX_STRING_LENGTH));
+    field.option_contents.push(
+        option.text.substring(0, fillConstants.MAX_STRING_LENGTH));
   }
 };
 
@@ -483,19 +524,20 @@
  * As the result of this method will be used by code written for Blink, match
  * the behavior on it.
  *
- * @param {FormControlElement|HTMLOptionElement} element An element to examine.
- * @return {string} The value for |element|.
+ * @param element An element to examine.
+ * @return The value for `element`.
  */
-__gCrWeb.fill.value = function(element) {
+gCrWeb.fill.value = function(
+    element: fillConstants.FormControlElement|HTMLOptionElement): string {
   let value = element.value;
-  if (__gCrWeb.fill.isSelectElement(element)) {
-    if (element.options.length > 0 && element.selectedIndex === 0 &&
-        element.options[0].disabled &&
-        !element.options[0].hasAttribute('selected')) {
-      for (let i = 0; i < element.options.length; i++) {
-        if (!element.options[i].disabled ||
-            element.options[i].hasAttribute('selected')) {
-          value = element.options[i].value;
+  if (gCrWeb.fill.isSelectElement(element)) {
+    const selectElement = element as HTMLSelectElement;
+    if (selectElement.options.length > 0 && selectElement.selectedIndex === 0 &&
+        selectElement.options[0]!.disabled &&
+        !selectElement.options[0]!.hasAttribute('selected')) {
+      for (const option of selectElement.options) {
+        if (!option.disabled || option.hasAttribute('selected')) {
+          value = option.value;
           break;
         }
       }
@@ -506,7 +548,7 @@
 
 /**
  * Returns the coalesced child text of the elements who's ids are found in
- * the |attribute| of |element|.
+ * the `attribute` of `element`.
  *
  * For example, given this document...
  *
@@ -524,7 +566,8 @@
  * of the field1 input element would be "Billing Name" and for field2 it would
  * be "Billing Address".
  */
-function coalesceTextByIdList(element, attribute) {
+function coalesceTextByIdList(
+  element: Element|null, attribute: string): string {
   if (!element) {
     return '';
   }
@@ -543,7 +586,7 @@
         return e !== null;
       })
       .map(function(n) {
-        return findChildText(n);
+        return findChildText(n!);
       })
       .filter(function(s) {
         return s.length > 0;
@@ -557,7 +600,7 @@
  * or the value of the aria-label attribute, with priority given to the
  * aria-labelledby text.
  */
-__gCrWeb.fill.getAriaLabel = function(element) {
+gCrWeb.fill.getAriaLabel = function(element: Element): string {
   let label = coalesceTextByIdList(element, 'aria-labelledby');
   if (!label) {
     label = element.getAttribute('aria-label') || '';
@@ -568,7 +611,7 @@
 /**
  * Returns the coalesced text referenced by the aria-describedby attribute.
  */
-__gCrWeb.fill.getAriaDescription = function(element) {
+gCrWeb.fill.getAriaDescription = function(element: Element): string {
   return coalesceTextByIdList(element, 'aria-describedby');
 };
 
@@ -580,15 +623,16 @@
  *     bool (const WebElement& element)
  * in chromium/src/components/autofill/content/renderer/form_cache.cc
  *
- * @param {!FormControlElement} element An element to examine.
- * @return {boolean} Whether the element is inside a <form> or <fieldset>.
+ * @param element An element to examine.
+ * @return Whether the element is inside a <form> or <fieldset>.
  */
-__gCrWeb.fill.isElementInsideFormOrFieldSet = function(element) {
+gCrWeb.fill.isElementInsideFormOrFieldSet = function(
+    element: fillConstants.FormControlElement): boolean {
   let parentNode = element.parentNode;
   while (parentNode) {
     if ((parentNode.nodeType === Node.ELEMENT_NODE) &&
-        (__gCrWeb.fill.hasTagName(parentNode, 'form') ||
-         __gCrWeb.fill.hasTagName(parentNode, 'fieldset'))) {
+        (gCrWeb.fill.hasTagName(parentNode, 'form') ||
+         gCrWeb.fill.hasTagName(parentNode, 'fieldset'))) {
       return true;
     }
     parentNode = parentNode.parentNode;
@@ -597,18 +641,19 @@
 };
 
 /**
- * @param {int} nextAvailableID Next available integer.
+ * @param nextAvailableID Next available integer.
  */
-__gCrWeb.fill['setUpForUniqueIDs'] = function(nextAvailableID) {
-  document[__gCrWeb.fill.ID_SYMBOL] = nextAvailableID;
+gCrWeb.fill['setUpForUniqueIDs'] = function(nextAvailableID: number): void {
+  const uniqueID = gCrWeb.fill.ID_SYMBOL;
+  document[uniqueID] = nextAvailableID;
 };
 
 /**
- * @param {Element} element Form or form input element.
+ * @param element Form or form input element.
  */
-__gCrWeb.fill.setUniqueIDIfNeeded = function(element) {
+gCrWeb.fill.setUniqueIDIfNeeded = function(element: IndexableElement): void {
   try {
-    const uniqueID = __gCrWeb.fill.ID_SYMBOL;
+    const uniqueID = gCrWeb.fill.ID_SYMBOL;
     // Do not assign element id value if the base value for the document
     // is not set.
     if (typeof document[uniqueID] !== 'undefined' &&
@@ -624,13 +669,14 @@
 };
 
 /**
- * @param {Element} element Form or form input element.
- * @return {String} Unique stable ID converted to string..
+ * @param element Form or form input element.
+ * @return Unique stable ID converted to string..
  */
-__gCrWeb.fill.getUniqueID = function(element) {
+gCrWeb.fill.getUniqueID = function(element: any): string {
   try {
-    const uniqueID = __gCrWeb.fill.ID_SYMBOL;
-    if (typeof element[uniqueID] !== 'undefined' && !isNaN(element[uniqueID])) {
+    const uniqueID = gCrWeb.fill.ID_SYMBOL;
+    if (typeof element[uniqueID]! !== 'undefined' &&
+        !isNaN(element[uniqueID]!)) {
       return element[uniqueID].toString();
     } else {
       return fillConstants.RENDERER_ID_NOT_SET;
@@ -641,10 +687,10 @@
 };
 
 /**
- * @param {int} Unique ID.
- * @return {Element} element Form or form input element.
+ * @param Unique ID.
+ * @return element Form or form input element.
  */
-__gCrWeb.fill.getElementByUniqueID = function(id) {
+gCrWeb.fill.getElementByUniqueID = function(id: number): Element | null {
   try {
     // TODO(crbug.com/1350973): WeakRef starts in 14.5, remove checks once 14 is
     // deprecated.
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/scrim/ScrimProperties.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/scrim/ScrimProperties.java
index c2a0c6b..9bb1e4d 100644
--- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/scrim/ScrimProperties.java
+++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/scrim/ScrimProperties.java
@@ -15,7 +15,6 @@
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.modelutil.PropertyModel.ReadableBooleanPropertyKey;
-import org.chromium.ui.modelutil.PropertyModel.ReadableIntPropertyKey;
 import org.chromium.ui.modelutil.PropertyModel.ReadableObjectPropertyKey;
 import org.chromium.ui.modelutil.PropertyModel.WritableBooleanPropertyKey;
 import org.chromium.ui.modelutil.PropertyModel.WritableFloatPropertyKey;
@@ -31,10 +30,10 @@
     @ColorInt public static final int INVALID_COLOR = Color.TRANSPARENT;
 
     /**
-     * The top margin of the scrim. This can be used to shrink the scrim to show items at the
-     * top of the screen.
+     * The top margin of the scrim. This can be used to shrink the scrim to show items at the top of
+     * the screen.
      */
-    public static final ReadableIntPropertyKey TOP_MARGIN = new ReadableIntPropertyKey();
+    public static final WritableIntPropertyKey TOP_MARGIN = new WritableIntPropertyKey();
 
     /** Whether the scrim should affect the status bar color. */
     public static final ReadableBooleanPropertyKey AFFECTS_STATUS_BAR =
diff --git a/components/cast_receiver/browser/application_client.h b/components/cast_receiver/browser/application_client.h
index ffeb866..ab1608fd 100644
--- a/components/cast_receiver/browser/application_client.h
+++ b/components/cast_receiver/browser/application_client.h
@@ -6,12 +6,12 @@
 #define COMPONENTS_CAST_RECEIVER_BROWSER_APPLICATION_CLIENT_H_
 
 #include <memory>
+#include <string_view>
 #include <vector>
 
 #include "base/functional/callback.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
-#include "base/strings/string_piece.h"
 #include "components/cast_receiver/browser/public/application_state_observer.h"
 #include "components/cast_receiver/browser/public/streaming_resolution_observer.h"
 
@@ -96,7 +96,7 @@
   void RemoveStreamingResolutionObserver(StreamingResolutionObserver* observer);
   void OnWebContentsCreated(content::WebContents* web_contents);
   using CorsExemptHeaderCallback =
-      base::RepeatingCallback<bool(base::StringPiece)>;
+      base::RepeatingCallback<bool(std::string_view)>;
   std::vector<std::unique_ptr<blink::URLLoaderThrottle>>
   CreateURLLoaderThrottles(
       const base::RepeatingCallback<content::WebContents*()>& wc_getter,
diff --git a/components/cast_receiver/browser/bindings_manager.cc b/components/cast_receiver/browser/bindings_manager.cc
index fd8145f..4248f31 100644
--- a/components/cast_receiver/browser/bindings_manager.cc
+++ b/components/cast_receiver/browser/bindings_manager.cc
@@ -21,7 +21,7 @@
 
 BindingsManager::~BindingsManager() = default;
 
-void BindingsManager::AddBinding(base::StringPiece binding_script) {
+void BindingsManager::AddBinding(std::string_view binding_script) {
   int id = next_script_id_++;
   bindings_[base::NumberToString(id)] = std::string(binding_script);
 }
@@ -39,8 +39,8 @@
   client_->OnError();
 }
 
-void BindingsManager::AddBinding(base::StringPiece binding_name,
-                                 base::StringPiece binding_script) {
+void BindingsManager::AddBinding(std::string_view binding_name,
+                                 std::string_view binding_script) {
   bindings_[std::string(binding_name)] = std::string(binding_script);
 }
 
diff --git a/components/cast_receiver/browser/bindings_manager.h b/components/cast_receiver/browser/bindings_manager.h
index c6368919..d676bb6 100644
--- a/components/cast_receiver/browser/bindings_manager.h
+++ b/components/cast_receiver/browser/bindings_manager.h
@@ -7,6 +7,7 @@
 
 #include <map>
 #include <memory>
+#include <string_view>
 
 #include "base/containers/flat_map.h"
 #include "base/memory/raw_ref.h"
@@ -47,7 +48,7 @@
   BindingsManager& operator=(const BindingsManager&) = delete;
   BindingsManager& operator=(BindingsManager&&) = delete;
 
-  void AddBinding(base::StringPiece binding_script);
+  void AddBinding(std::string_view binding_script);
 
   // Configures the |message_port_connector_| for use with this |web_contents|
   // and connects it to the bindings service.
@@ -61,8 +62,8 @@
   void OnError() override;
 
   // cast_api_bindings::Manager overrides.
-  void AddBinding(base::StringPiece binding_name,
-                  base::StringPiece binding_script) override;
+  void AddBinding(std::string_view binding_name,
+                  std::string_view binding_script) override;
 
   int next_script_id_{0};
 
diff --git a/components/cast_receiver/browser/bindings_message_port_connector.cc b/components/cast_receiver/browser/bindings_message_port_connector.cc
index 38e69905..ebab63c 100644
--- a/components/cast_receiver/browser/bindings_message_port_connector.cc
+++ b/components/cast_receiver/browser/bindings_message_port_connector.cc
@@ -28,9 +28,9 @@
 bool AddReturnValue(
     base::WeakPtr<BindingsMessagePortConnector> ptr,
     base::RepeatingCallback<
-        void(base::StringPiece,
-             std::unique_ptr<cast_api_bindings::MessagePort>)> callback,
-    base::StringPiece port_name,
+        void(std::string_view, std::unique_ptr<cast_api_bindings::MessagePort>)>
+        callback,
+    std::string_view port_name,
     std::unique_ptr<cast_api_bindings::MessagePort> port) {
   callback.Run(std::move(port_name), std::move(port));
   return !!ptr;
@@ -85,12 +85,12 @@
 
 void BindingsMessagePortConnector::AddBeforeLoadJavaScript(
     uint64_t id,
-    base::StringPiece script) {
+    std::string_view script) {
   script_injector_.AddScriptForAllOrigins(id, std::string(script));
 }
 
 void BindingsMessagePortConnector::OnPortConnected(
-    base::StringPiece port_name,
+    std::string_view port_name,
     std::unique_ptr<cast_api_bindings::MessagePort> port) {
   client_->Connect(
       std::string(port_name),
diff --git a/components/cast_receiver/browser/bindings_message_port_connector.h b/components/cast_receiver/browser/bindings_message_port_connector.h
index 701cbf7..a6e80ca 100644
--- a/components/cast_receiver/browser/bindings_message_port_connector.h
+++ b/components/cast_receiver/browser/bindings_message_port_connector.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_CAST_RECEIVER_BROWSER_BINDINGS_MESSAGE_PORT_CONNECTOR_H_
 
 #include <string>
+#include <string_view>
 #include <vector>
 
 #include "base/memory/raw_ptr.h"
@@ -74,10 +75,10 @@
 
  private:
   // Adds a new binding.
-  void AddBeforeLoadJavaScript(uint64_t id, base::StringPiece script);
+  void AddBeforeLoadJavaScript(uint64_t id, std::string_view script);
 
   // Callback for RegisterPortHandler().
-  void OnPortConnected(base::StringPiece port_name,
+  void OnPortConnected(std::string_view port_name,
                        std::unique_ptr<cast_api_bindings::MessagePort> port);
 
   // PageStateObserver implementation:
diff --git a/components/cast_receiver/browser/public/content_browser_client_mixins.h b/components/cast_receiver/browser/public/content_browser_client_mixins.h
index 2bcb087..3f4c126 100644
--- a/components/cast_receiver/browser/public/content_browser_client_mixins.h
+++ b/components/cast_receiver/browser/public/content_browser_client_mixins.h
@@ -6,10 +6,10 @@
 #define COMPONENTS_CAST_RECEIVER_BROWSER_PUBLIC_CONTENT_BROWSER_CLIENT_MIXINS_H_
 
 #include <memory>
+#include <string_view>
 #include <vector>
 
 #include "base/functional/callback.h"
-#include "base/strings/string_piece.h"
 #include "components/cast_receiver/browser/runtime_application_dispatcher_impl.h"
 
 namespace blink {
@@ -73,7 +73,7 @@
 
   // To be called by the ContentBrowserClient function of the same name.
   using CorsExemptHeaderCallback =
-      base::RepeatingCallback<bool(base::StringPiece)>;
+      base::RepeatingCallback<bool(std::string_view)>;
   virtual std::vector<std::unique_ptr<blink::URLLoaderThrottle>>
   CreateURLLoaderThrottles(
       const base::RepeatingCallback<content::WebContents*()>& wc_getter,
diff --git a/components/cast_receiver/browser/public/message_port_service.h b/components/cast_receiver/browser/public/message_port_service.h
index 0bfed5a..490059c 100644
--- a/components/cast_receiver/browser/public/message_port_service.h
+++ b/components/cast_receiver/browser/public/message_port_service.h
@@ -6,9 +6,9 @@
 #define COMPONENTS_CAST_RECEIVER_BROWSER_PUBLIC_MESSAGE_PORT_SERVICE_H_
 
 #include <memory>
+#include <string_view>
 
 #include "base/functional/callback.h"
-#include "base/strings/string_piece.h"
 
 namespace cast_api_bindings {
 class MessagePort;
@@ -28,7 +28,7 @@
 
   // Connects |port| to the remote port with name |port_name| asynchronously.
   virtual void ConnectToPortAsync(
-      base::StringPiece port_name,
+      std::string_view port_name,
       std::unique_ptr<cast_api_bindings::MessagePort> port) = 0;
 
   // Registers a port opened locally via a port transfer. This allocates a new
diff --git a/components/cast_receiver/common/public/status.h b/components/cast_receiver/common/public/status.h
index a18384e..214a96c9 100644
--- a/components/cast_receiver/common/public/status.h
+++ b/components/cast_receiver/common/public/status.h
@@ -7,8 +7,7 @@
 
 #include <ostream>
 #include <string>
-
-#include "base/strings/string_piece.h"
+#include <string_view>
 
 namespace cast_receiver {
 
@@ -65,7 +64,7 @@
   StatusCode code() const;
 
   // Returns the error message of this status.
-  base::StringPiece message() const;
+  std::string_view message() const;
 
   // Returns `true` if `this->code() == cast_receiver::StatusCode::kOk`.
   [[nodiscard]] bool ok() const;
@@ -86,7 +85,7 @@
   return code_;
 }
 
-inline base::StringPiece Status::message() const {
+inline std::string_view Status::message() const {
   return message_;
 }
 
diff --git a/components/cast_receiver/renderer/content_renderer_client_mixins_impl.cc b/components/cast_receiver/renderer/content_renderer_client_mixins_impl.cc
index 9c1e276..35f8b8f9e 100644
--- a/components/cast_receiver/renderer/content_renderer_client_mixins_impl.cc
+++ b/components/cast_receiver/renderer/content_renderer_client_mixins_impl.cc
@@ -97,7 +97,7 @@
 }
 
 bool ContentRendererClientMixinsImpl::IsCorsExemptHeader(
-    base::StringPiece header) {
+    std::string_view header) {
   return is_cors_exempt_header_callback_.Run(header);
 }
 
diff --git a/components/cast_receiver/renderer/content_renderer_client_mixins_impl.h b/components/cast_receiver/renderer/content_renderer_client_mixins_impl.h
index 96163ce..d867dc5 100644
--- a/components/cast_receiver/renderer/content_renderer_client_mixins_impl.h
+++ b/components/cast_receiver/renderer/content_renderer_client_mixins_impl.h
@@ -6,10 +6,10 @@
 #define COMPONENTS_CAST_RECEIVER_RENDERER_CONTENT_RENDERER_CLIENT_MIXINS_IMPL_H_
 
 #include <memory>
+#include <string_view>
 
 #include "base/containers/flat_map.h"
 #include "base/functional/callback_forward.h"
-#include "base/strings/string_piece.h"
 #include "components/cast_receiver/renderer/public/content_renderer_client_mixins.h"
 #include "components/cast_receiver/renderer/wrapping_url_loader_throttle_provider.h"
 
@@ -63,7 +63,7 @@
   // WrappingURLLoaderThrottleProvider::Client implementation.
   UrlRewriteRulesProvider* GetUrlRewriteRulesProvider(
       const blink::LocalFrameToken& frame_token) override;
-  bool IsCorsExemptHeader(base::StringPiece header) override;
+  bool IsCorsExemptHeader(std::string_view header) override;
 
   IsCorsExemptHeadersCallback is_cors_exempt_header_callback_;
 
diff --git a/components/cast_receiver/renderer/public/content_renderer_client_mixins.h b/components/cast_receiver/renderer/public/content_renderer_client_mixins.h
index 38d7c3f4..2d8d796 100644
--- a/components/cast_receiver/renderer/public/content_renderer_client_mixins.h
+++ b/components/cast_receiver/renderer/public/content_renderer_client_mixins.h
@@ -6,9 +6,9 @@
 #define COMPONENTS_CAST_RECEIVER_RENDERER_PUBLIC_CONTENT_RENDERER_CLIENT_MIXINS_H_
 
 #include <memory>
+#include <string_view>
 
 #include "base/functional/callback_forward.h"
-#include "base/strings/string_piece.h"
 
 namespace blink {
 class URLLoaderThrottleProvider;
@@ -30,7 +30,7 @@
 class ContentRendererClientMixins {
  public:
   using IsCorsExemptHeadersCallback =
-      base::RepeatingCallback<bool(base::StringPiece)>;
+      base::RepeatingCallback<bool(std::string_view)>;
   static std::unique_ptr<ContentRendererClientMixins> Create(
       IsCorsExemptHeadersCallback is_cors_exempt_header_callback);
 
diff --git a/components/cast_receiver/renderer/wrapping_url_loader_throttle_provider.h b/components/cast_receiver/renderer/wrapping_url_loader_throttle_provider.h
index 42ffcc8..b8f2d0e 100644
--- a/components/cast_receiver/renderer/wrapping_url_loader_throttle_provider.h
+++ b/components/cast_receiver/renderer/wrapping_url_loader_throttle_provider.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_CAST_RECEIVER_RENDERER_WRAPPING_URL_LOADER_THROTTLE_PROVIDER_H_
 
 #include <memory>
+#include <string_view>
 
 #include "base/containers/flat_map.h"
 #include "base/functional/callback_forward.h"
@@ -31,7 +32,7 @@
         const blink::LocalFrameToken& frame_token) = 0;
 
     // Returns whether |header| is a cors exempt header.
-    virtual bool IsCorsExemptHeader(base::StringPiece header) = 0;
+    virtual bool IsCorsExemptHeader(std::string_view header) = 0;
   };
 
   // |client| is expected to outlive this instance.
diff --git a/components/cast_streaming/browser/cast_message_port_impl.cc b/components/cast_streaming/browser/cast_message_port_impl.cc
index 749bc04..155b968 100644
--- a/components/cast_streaming/browser/cast_message_port_impl.cc
+++ b/components/cast_streaming/browser/cast_message_port_impl.cc
@@ -235,7 +235,7 @@
 }
 
 bool CastMessagePortImpl::OnMessage(
-    base::StringPiece message,
+    std::string_view message,
     std::vector<std::unique_ptr<cast_api_bindings::MessagePort>> ports) {
   DVLOG(3) << __func__;
 
diff --git a/components/cast_streaming/browser/cast_message_port_impl.h b/components/cast_streaming/browser/cast_message_port_impl.h
index 69ebdcd..c98fab9 100644
--- a/components/cast_streaming/browser/cast_message_port_impl.h
+++ b/components/cast_streaming/browser/cast_message_port_impl.h
@@ -7,6 +7,8 @@
 #ifndef COMPONENTS_CAST_STREAMING_BROWSER_CAST_MESSAGE_PORT_IMPL_H_
 #define COMPONENTS_CAST_STREAMING_BROWSER_CAST_MESSAGE_PORT_IMPL_H_
 
+#include <string_view>
+
 #include "base/functional/callback.h"
 #include "base/memory/raw_ptr.h"
 #include "components/cast/message_port/message_port.h"
@@ -51,7 +53,7 @@
                           const std::string& message);
 
   // cast_api_bindings::MessagePort::Receiver implementation.
-  bool OnMessage(base::StringPiece message,
+  bool OnMessage(std::string_view message,
                  std::vector<std::unique_ptr<cast_api_bindings::MessagePort>>
                      ports) override;
   void OnPipeError() override;
diff --git a/components/cast_streaming/common/app_ids.cc b/components/cast_streaming/common/app_ids.cc
index 3d4b44f..f9e0946 100644
--- a/components/cast_streaming/common/app_ids.cc
+++ b/components/cast_streaming/common/app_ids.cc
@@ -4,9 +4,11 @@
 
 #include "components/cast_streaming/common/public/app_ids.h"
 
+#include <string_view>
+
 namespace cast_streaming {
 
-bool IsStreamingReceiverAppId(base::StringPiece app_id) {
+bool IsStreamingReceiverAppId(std::string_view app_id) {
   const std::string app_id_string(app_id.data(), app_id.length());
   return openscreen::cast::IsCastStreamingReceiverAppId(app_id_string);
 }
diff --git a/components/cast_streaming/common/message_serialization.cc b/components/cast_streaming/common/message_serialization.cc
index f0c47b7e..7f18a06 100644
--- a/components/cast_streaming/common/message_serialization.cc
+++ b/components/cast_streaming/common/message_serialization.cc
@@ -51,7 +51,7 @@
     }
     )";
 
-bool DeserializeCastMessage(base::StringPiece buffer,
+bool DeserializeCastMessage(std::string_view buffer,
                             std::string* sender_id,
                             std::string* message_namespace,
                             std::string* message) {
diff --git a/components/cast_streaming/common/message_serialization.h b/components/cast_streaming/common/message_serialization.h
index db717ab..2b719a5 100644
--- a/components/cast_streaming/common/message_serialization.h
+++ b/components/cast_streaming/common/message_serialization.h
@@ -6,8 +6,7 @@
 #define COMPONENTS_CAST_STREAMING_COMMON_MESSAGE_SERIALIZATION_H_
 
 #include <string>
-
-#include "base/strings/string_piece.h"
+#include <string_view>
 
 namespace cast_streaming {
 
@@ -42,7 +41,7 @@
 
 // Parses |buffer| data into |sender_id|, |message_namespace| and |message|.
 // Returns true on success.
-bool DeserializeCastMessage(base::StringPiece buffer,
+bool DeserializeCastMessage(std::string_view buffer,
                             std::string* sender_id,
                             std::string* message_namespace,
                             std::string* message);
diff --git a/components/cast_streaming/common/public/app_ids.h b/components/cast_streaming/common/public/app_ids.h
index 3e443dc..18ef357 100644
--- a/components/cast_streaming/common/public/app_ids.h
+++ b/components/cast_streaming/common/public/app_ids.h
@@ -5,14 +5,14 @@
 #ifndef COMPONENTS_CAST_STREAMING_COMMON_PUBLIC_APP_IDS_H_
 #define COMPONENTS_CAST_STREAMING_COMMON_PUBLIC_APP_IDS_H_
 
-#include "third_party/openscreen/src/cast/common/public/cast_streaming_app_ids.h"
+#include <string_view>
 
-#include "base/strings/string_piece.h"
+#include "third_party/openscreen/src/cast/common/public/cast_streaming_app_ids.h"
 
 namespace cast_streaming {
 
 // Returns true if |app_id| is associated with a streaming application.
-bool IsStreamingReceiverAppId(base::StringPiece app_id);
+bool IsStreamingReceiverAppId(std::string_view app_id);
 
 // Returns the app ID for the audio and video streaming receiver used by iOS
 // apps.
diff --git a/components/cast_streaming/test/cast_message_port_sender_impl.cc b/components/cast_streaming/test/cast_message_port_sender_impl.cc
index 904bcf7e..4642a30 100644
--- a/components/cast_streaming/test/cast_message_port_sender_impl.cc
+++ b/components/cast_streaming/test/cast_message_port_sender_impl.cc
@@ -74,7 +74,7 @@
 }
 
 bool CastMessagePortSenderImpl::OnMessage(
-    base::StringPiece message,
+    std::string_view message,
     std::vector<std::unique_ptr<cast_api_bindings::MessagePort>> ports) {
   VLOG(3) << __func__;
 
diff --git a/components/cast_streaming/test/cast_message_port_sender_impl.h b/components/cast_streaming/test/cast_message_port_sender_impl.h
index 05f8e9d..f31c3f0 100644
--- a/components/cast_streaming/test/cast_message_port_sender_impl.h
+++ b/components/cast_streaming/test/cast_message_port_sender_impl.h
@@ -5,6 +5,8 @@
 #ifndef COMPONENTS_CAST_STREAMING_TEST_CAST_MESSAGE_PORT_SENDER_IMPL_H_
 #define COMPONENTS_CAST_STREAMING_TEST_CAST_MESSAGE_PORT_SENDER_IMPL_H_
 
+#include <string_view>
+
 #include "base/functional/callback.h"
 #include "base/memory/raw_ptr.h"
 #include "base/threading/thread_checker.h"
@@ -42,7 +44,7 @@
   void MaybeClose();
 
   // cast_api_bindings::MessagePort::Receiver implementation.
-  bool OnMessage(base::StringPiece message,
+  bool OnMessage(std::string_view message,
                  std::vector<std::unique_ptr<cast_api_bindings::MessagePort>>
                      ports) override;
   void OnPipeError() override;
diff --git a/components/certificate_transparency/data/log_list.json b/components/certificate_transparency/data/log_list.json
index 8e8d9c9..b1348f8 100644
--- a/components/certificate_transparency/data/log_list.json
+++ b/components/certificate_transparency/data/log_list.json
@@ -1,6 +1,6 @@
 {
-  "version": "28.18",
-  "log_list_timestamp": "2023-12-17T12:54:36Z",
+  "version": "28.19",
+  "log_list_timestamp": "2023-12-18T12:57:38Z",
   "operators": [
     {
       "name": "Google",
diff --git a/components/commerce/core/commerce_constants.cc b/components/commerce/core/commerce_constants.cc
index c1d9fe33..33895db 100644
--- a/components/commerce/core/commerce_constants.cc
+++ b/components/commerce/core/commerce_constants.cc
@@ -14,34 +14,17 @@
 const char kChromeUIShoppingInsightsSidePanelUrl[] =
     "chrome://shopping-insights-side-panel.top-chrome";
 
-const char kOAuthScope[] = "https://www.googleapis.com/auth/chromememex";
-
-const char kOAuthName[] = "chromememex_svc";
+const char kContentType[] = "application/json; charset=UTF-8";
 
 const char kDeleteHttpMethod[] = "DELETE";
 
-const char kGetHttpMethod[] = "GET";
-
-const char kPostHttpMethod[] = "POST";
-
-const char kContentType[] = "application/json; charset=UTF-8";
-
 const char kEmptyPostData[] = "";
 
-const char kUTMSourceLabel[] = "utm_source";
+const char kGetHttpMethod[] = "GET";
 
-const char kUTMMediumLabel[] = "utm_medium";
+const char kOAuthName[] = "chromememex_svc";
 
-const char kUTMCampaignLabel[] = "utm_campaign";
-
-const char kUTMSourceValue[] = "chrome";
-
-const char kUTMMediumValue[] = "app";
-
-const char kUTMCampaignValueForDiscounts[] =
-    "chrome-history-cluster-with-discount";
-
-const char kUTMPrefix[] = "utm_";
+const char kOAuthScope[] = "https://www.googleapis.com/auth/chromememex";
 
 const char kOgImage[] = "image";
 const char kOgPriceAmount[] = "price:amount";
@@ -53,4 +36,26 @@
 const char kOgTypeOgProduct[] = "product";
 const char kOgTypeProductItem[] = "product.item";
 
+const char kPostHttpMethod[] = "POST";
+
+const char kUTMCampaignLabel[] = "utm_campaign";
+
+const char kUTMCampaignValueForCartDiscount[] = "chrome-cart-discount-on";
+
+const char kUTMCampaignValueForCartNoDiscount[] = "chrome-cart-discount-off";
+
+const char kUTMCampaignValueForChromeCart[] = "chrome-cart";
+
+const char kUTMCampaignValueForDiscounts[] =
+    "chrome-history-cluster-with-discount";
+
+const char kUTMMediumLabel[] = "utm_medium";
+
+const char kUTMMediumValue[] = "app";
+
+const char kUTMPrefix[] = "utm_";
+
+const char kUTMSourceLabel[] = "utm_source";
+
+const char kUTMSourceValue[] = "chrome";
 }  // namespace commerce
diff --git a/components/commerce/core/commerce_constants.h b/components/commerce/core/commerce_constants.h
index 19cabb95..9a8cbae 100644
--- a/components/commerce/core/commerce_constants.h
+++ b/components/commerce/core/commerce_constants.h
@@ -16,49 +16,24 @@
 // The url for the shopping insights side panel page.
 extern const char kChromeUIShoppingInsightsSidePanelUrl[];
 
+// Content type for network request.
+extern const char kContentType[];
+
 // Http DELETE method.
 extern const char kDeleteHttpMethod[];
 
+// Empty data for POST request.
+extern const char kEmptyPostData[];
+
 // Http GET method.
 extern const char kGetHttpMethod[];
 
-// Http POST method.
-extern const char kPostHttpMethod[];
-
 // OAuth name used for network request.
 extern const char kOAuthName[];
 
 // OAuth scope used for network request.
 extern const char kOAuthScope[];
 
-// Content type for network request.
-extern const char kContentType[];
-
-// Empty data for POST request.
-extern const char kEmptyPostData[];
-
-// Please do not use below UTM constants beyond commerce use cases.
-// UTM source label.
-extern const char kUTMSourceLabel[];
-
-// UTM medium label.
-extern const char kUTMMediumLabel[];
-
-// UTM campaign label.
-extern const char kUTMCampaignLabel[];
-
-// General UTM source value.
-extern const char kUTMSourceValue[];
-
-// General UTM medium value.
-extern const char kUTMMediumValue[];
-
-// UTM campaign value for discounts in history clusters.
-extern const char kUTMCampaignValueForDiscounts[];
-
-// Prefix of UTM labels, including the underscore.
-extern const char kUTMPrefix[];
-
 // Open graph keys.
 extern const char kOgImage[];
 extern const char kOgPriceAmount[];
@@ -70,6 +45,40 @@
 // Specific open graph values we're interested in.
 extern const char kOgTypeOgProduct[];
 extern const char kOgTypeProductItem[];
+
+// Http POST method.
+extern const char kPostHttpMethod[];
+
+// Please do not use below UTM constants beyond commerce use cases.
+// UTM campaign label.
+extern const char kUTMCampaignLabel[];
+
+// UTM campaign value for partner merchant carts when discount is enabled.
+extern const char kUTMCampaignValueForCartDiscount[];
+
+// UTM campaign value for partner merchant carts when discount is disabled.
+extern const char kUTMCampaignValueForCartNoDiscount[];
+
+// UTM campaign value for non-partner merchant carts.
+extern const char kUTMCampaignValueForChromeCart[];
+
+// UTM campaign value for discounts in history clusters.
+extern const char kUTMCampaignValueForDiscounts[];
+
+// UTM medium label.
+extern const char kUTMMediumLabel[];
+
+// General UTM medium value.
+extern const char kUTMMediumValue[];
+
+// Prefix of UTM labels, including the underscore.
+extern const char kUTMPrefix[];
+
+// UTM source label.
+extern const char kUTMSourceLabel[];
+
+// General UTM source value.
+extern const char kUTMSourceValue[];
 }  // namespace commerce
 
 #endif  // COMPONENTS_COMMERCE_CORE_COMMERCE_CONSTANTS_H_
diff --git a/components/content_settings/core/browser/cookie_settings_unittest.cc b/components/content_settings/core/browser/cookie_settings_unittest.cc
index 8472c68..8e521671 100644
--- a/components/content_settings/core/browser/cookie_settings_unittest.cc
+++ b/components/content_settings/core/browser/cookie_settings_unittest.cc
@@ -314,7 +314,9 @@
  protected:
   bool ShouldDeleteCookieOnExit(const std::string& domain, bool is_https) {
     return cookie_settings_->ShouldDeleteCookieOnExit(
-        cookie_settings_->GetCookieSettings(), domain, is_https);
+        cookie_settings_->GetCookieSettings(), domain,
+        is_https ? net::CookieSourceScheme::kSecure
+                 : net::CookieSourceScheme::kNonSecure);
   }
 
   // There must be a valid SingleThreadTaskRunner::CurrentDefaultHandle in
diff --git a/components/content_settings/core/common/cookie_settings_base.cc b/components/content_settings/core/common/cookie_settings_base.cc
index f638c92..c54776b 100644
--- a/components/content_settings/core/common/cookie_settings_base.cc
+++ b/components/content_settings/core/common/cookie_settings_base.cc
@@ -15,6 +15,7 @@
 #include "net/base/features.h"
 #include "net/base/net_errors.h"
 #include "net/base/url_util.h"
+#include "net/cookies/cookie_constants.h"
 #include "net/cookies/cookie_setting_override.h"
 #include "net/cookies/cookie_util.h"
 #include "net/cookies/site_for_cookies.h"
@@ -95,8 +96,11 @@
 bool CookieSettingsBase::ShouldDeleteCookieOnExit(
     const ContentSettingsForOneType& cookie_settings,
     const std::string& domain,
-    bool is_https) const {
-  GURL origin = net::cookie_util::CookieOriginToURL(domain, is_https);
+    net::CookieSourceScheme scheme) const {
+  // Cookies with an unknown (kUnset) scheme will be treated as having a not
+  // secure scheme.
+  GURL origin = net::cookie_util::CookieOriginToURL(
+      domain, scheme == net::CookieSourceScheme::kSecure);
   // Pass GURL() as first_party_url since we don't know the context and
   // don't want to match against (*, exception) pattern.
   // No overrides are given since existing ones only pertain to 3P checks.
@@ -110,10 +114,11 @@
     return false;
   }
   // Non-secure cookies are readable by secure sites. We need to check for
-  // https pattern if http is not allowed. The section below is independent
-  // of the scheme so we can just retry from here.
-  if (!is_https) {
-    return ShouldDeleteCookieOnExit(cookie_settings, domain, true);
+  // the secure pattern if non-secure is not allowed. The section below is
+  // independent of the scheme so we can just retry from here.
+  if (scheme != net::CookieSourceScheme::kSecure) {
+    return ShouldDeleteCookieOnExit(cookie_settings, domain,
+                                    net::CookieSourceScheme::kSecure);
   }
   // Check if there is a more precise rule that "domain matches" this cookie.
   bool matches_session_only_rule = false;
diff --git a/components/content_settings/core/common/cookie_settings_base.h b/components/content_settings/core/common/cookie_settings_base.h
index ccc37cc1..731c6ec3 100644
--- a/components/content_settings/core/common/cookie_settings_base.h
+++ b/components/content_settings/core/common/cookie_settings_base.h
@@ -164,7 +164,7 @@
   bool ShouldDeleteCookieOnExit(
       const ContentSettingsForOneType& cookie_settings,
       const std::string& domain,
-      bool is_https) const;
+      net::CookieSourceScheme scheme) const;
 
   // Returns true if the page identified by (`url`, `site_for_cookies`,
   // `top_frame_origin`) is allowed to access (i.e., read or write) cookies.
diff --git a/components/content_settings/core/common/cookie_settings_base_unittest.cc b/components/content_settings/core/common/cookie_settings_base_unittest.cc
index df27276..3933165 100644
--- a/components/content_settings/core/common/cookie_settings_base_unittest.cc
+++ b/components/content_settings/core/common/cookie_settings_base_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/notreached.h"
 #include "base/test/scoped_feature_list.h"
 #include "net/base/features.h"
+#include "net/cookies/cookie_constants.h"
 #include "net/cookies/cookie_setting_override.h"
 #include "net/cookies/cookie_util.h"
 #include "net/cookies/site_for_cookies.h"
@@ -83,13 +84,15 @@
 TEST(CookieSettingsBaseTest, ShouldDeleteSessionOnly) {
   CallbackCookieSettings settings(base::BindRepeating(
       [](const GURL&) { return CONTENT_SETTING_SESSION_ONLY; }));
-  EXPECT_TRUE(settings.ShouldDeleteCookieOnExit({}, kDomain, false));
+  EXPECT_TRUE(settings.ShouldDeleteCookieOnExit(
+      {}, kDomain, net::CookieSourceScheme::kNonSecure));
 }
 
 TEST(CookieSettingsBaseTest, ShouldNotDeleteAllowed) {
   CallbackCookieSettings settings(
       base::BindRepeating([](const GURL&) { return CONTENT_SETTING_ALLOW; }));
-  EXPECT_FALSE(settings.ShouldDeleteCookieOnExit({}, kDomain, false));
+  EXPECT_FALSE(settings.ShouldDeleteCookieOnExit(
+      {}, kDomain, net::CookieSourceScheme::kNonSecure));
 }
 
 TEST(CookieSettingsBaseTest, ShouldNotDeleteAllowedHttps) {
@@ -97,29 +100,34 @@
     return url.SchemeIsCryptographic() ? CONTENT_SETTING_ALLOW
                                        : CONTENT_SETTING_BLOCK;
   }));
-  EXPECT_FALSE(settings.ShouldDeleteCookieOnExit({}, kDomain, false));
-  EXPECT_FALSE(settings.ShouldDeleteCookieOnExit({}, kDomain, true));
+  EXPECT_FALSE(settings.ShouldDeleteCookieOnExit(
+      {}, kDomain, net::CookieSourceScheme::kNonSecure));
+  EXPECT_FALSE(settings.ShouldDeleteCookieOnExit(
+      {}, kDomain, net::CookieSourceScheme::kSecure));
 }
 
 TEST(CookieSettingsBaseTest, ShouldDeleteDomainSettingSessionOnly) {
   CallbackCookieSettings settings(
       base::BindRepeating([](const GURL&) { return CONTENT_SETTING_BLOCK; }));
   EXPECT_TRUE(settings.ShouldDeleteCookieOnExit(
-      {CreateSetting(CONTENT_SETTING_SESSION_ONLY)}, kDomain, false));
+      {CreateSetting(CONTENT_SETTING_SESSION_ONLY)}, kDomain,
+      net::CookieSourceScheme::kNonSecure));
 }
 
 TEST(CookieSettingsBaseTest, ShouldDeleteDomainThirdPartySettingSessionOnly) {
   CallbackCookieSettings settings(
       base::BindRepeating([](const GURL&) { return CONTENT_SETTING_BLOCK; }));
   EXPECT_TRUE(settings.ShouldDeleteCookieOnExit(
-      {CreateThirdPartySetting(CONTENT_SETTING_SESSION_ONLY)}, kDomain, false));
+      {CreateThirdPartySetting(CONTENT_SETTING_SESSION_ONLY)}, kDomain,
+      net::CookieSourceScheme::kNonSecure));
 }
 
 TEST(CookieSettingsBaseTest, ShouldNotDeleteDomainSettingAllow) {
   CallbackCookieSettings settings(
       base::BindRepeating([](const GURL&) { return CONTENT_SETTING_BLOCK; }));
   EXPECT_FALSE(settings.ShouldDeleteCookieOnExit(
-      {CreateSetting(CONTENT_SETTING_ALLOW)}, kDomain, false));
+      {CreateSetting(CONTENT_SETTING_ALLOW)}, kDomain,
+      net::CookieSourceScheme::kNonSecure));
 }
 
 TEST(CookieSettingsBaseTest,
@@ -129,21 +137,23 @@
   EXPECT_FALSE(settings.ShouldDeleteCookieOnExit(
       {CreateSetting(CONTENT_SETTING_SESSION_ONLY),
        CreateSetting(CONTENT_SETTING_ALLOW)},
-      kDomain, false));
+      kDomain, net::CookieSourceScheme::kNonSecure));
 }
 
 TEST(CookieSettingsBaseTest, ShouldNotDeleteDomainSettingBlock) {
   CallbackCookieSettings settings(
       base::BindRepeating([](const GURL&) { return CONTENT_SETTING_BLOCK; }));
   EXPECT_FALSE(settings.ShouldDeleteCookieOnExit(
-      {CreateSetting(CONTENT_SETTING_BLOCK)}, kDomain, false));
+      {CreateSetting(CONTENT_SETTING_BLOCK)}, kDomain,
+      net::CookieSourceScheme::kNonSecure));
 }
 
 TEST(CookieSettingsBaseTest, ShouldNotDeleteNoDomainMatch) {
   CallbackCookieSettings settings(
       base::BindRepeating([](const GURL&) { return CONTENT_SETTING_BLOCK; }));
   EXPECT_FALSE(settings.ShouldDeleteCookieOnExit(
-      {CreateSetting(CONTENT_SETTING_SESSION_ONLY)}, "other.com", false));
+      {CreateSetting(CONTENT_SETTING_SESSION_ONLY)}, "other.com",
+      net::CookieSourceScheme::kNonSecure));
 }
 
 TEST(CookieSettingsBaseTest, ShouldNotDeleteNoThirdPartyDomainMatch) {
@@ -151,7 +161,7 @@
       base::BindRepeating([](const GURL&) { return CONTENT_SETTING_BLOCK; }));
   EXPECT_FALSE(settings.ShouldDeleteCookieOnExit(
       {CreateThirdPartySetting(CONTENT_SETTING_SESSION_ONLY)}, "other.com",
-      false));
+      net::CookieSourceScheme::kNonSecure));
 }
 
 TEST(CookieSettingsBaseTest, CookieAccessNotAllowedWithBlockedSetting) {
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/NQETest.java b/components/cronet/android/test/javatests/src/org/chromium/net/NQETest.java
index 7710eca..90dff49 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/NQETest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/NQETest.java
@@ -161,20 +161,7 @@
     @Test
     @SmallTest
     public void testQuicDisabled() throws Exception {
-        // Set up HistogramWatcher before starting CronetEngine. This is because the
-        // HistogramWatcher takes a snapshot of the starting sample count and uses the delta of this
-        // and the count at assertExpected() call time to confirm that new samples are logged.
         UmaRecorderHolder.onLibraryLoaded(); // Hackish workaround to crbug.com/1338919
-        var writeCountHistogram =
-                HistogramWatcher.newBuilder()
-                        .expectIntRecord("NQE.Prefs.WriteCount", 1)
-                        .allowExtraRecordsForHistogramsAbove()
-                        .build();
-        var readCountHistogram =
-                HistogramWatcher.newBuilder()
-                        .expectIntRecord("NQE.Prefs.ReadCount", 1)
-                        .allowExtraRecordsForHistogramsAbove()
-                        .build();
         assertThat(RttThroughputValues.INVALID_RTT_THROUGHPUT).isLessThan(0);
         Executor listenersExecutor = Executors.newSingleThreadExecutor(new ExecutorThreadFactory());
         TestNetworkQualityRttListener rttListener =
@@ -227,9 +214,6 @@
 
         assertThat(throughputListener.throughputObservationCount()).isGreaterThan(0);
 
-        // Prefs must be read at startup.
-        readCountHistogram.assertExpected();
-
         // Check RTT observation count after throughput observation has been received. This ensures
         // that executor has finished posting the RTT observation to the RTT listeners.
         assertThat(rttListener.rttObservationCount()).isGreaterThan(0);
@@ -274,7 +258,6 @@
         assertThat(prefsFileContainsString("network_qualities")).isTrue();
 
         cronetEngine.shutdown();
-        writeCountHistogram.assertExpected();
     }
 
     @Test
@@ -285,30 +268,6 @@
 
         UmaRecorderHolder.onLibraryLoaded(); // Hackish workaround to crbug.com/1338919
         for (int i = 0; i <= 1; ++i) {
-            // Set up HistogramWatcher before starting CronetEngine. This is because the
-            // HistogramWatcher takes a snapshot of the starting sample count and uses the delta of
-            // this and the count at assertExpected() call time to confirm that new samples are
-            // logged.
-            HistogramWatcher readCountHistogram =
-                    HistogramWatcher.newBuilder()
-                            .expectIntRecord("NQE.Prefs.ReadCount", 1)
-                            .allowExtraRecordsForHistogramsAbove()
-                            .build();
-
-            // Stored network quality in the pref should be read in the second iteration.
-            HistogramWatcher readPrefsSizeHistogram;
-            if (i == 0) {
-                readPrefsSizeHistogram =
-                        HistogramWatcher.newBuilder()
-                                .expectIntRecord("NQE.Prefs.ReadSize", 0)
-                                .build();
-            } else {
-                readPrefsSizeHistogram =
-                        HistogramWatcher.newBuilder()
-                                .expectIntRecord("NQE.Prefs.ReadSize", 1)
-                                .allowExtraRecordsForHistogramsAbove()
-                                .build();
-            }
 
             // NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_CACHED_ESTIMATE: 3
             HistogramWatcher cachedRttHistogram =
@@ -357,9 +316,6 @@
             // Wait for RTT observation (at the URL request layer) to be posted.
             rttListener.waitUntilFirstUrlRequestRTTReceived();
 
-            // Prefs must be read at startup.
-            readCountHistogram.assertExpected();
-
             // Check RTT observation count after throughput observation has been received. This
             // ensures that executor has finished posting the RTT observation to the RTT
             // listeners.
@@ -377,7 +333,6 @@
                 assertThat(prefsFileContainsString("network_qualities")).isTrue();
             }
 
-            readPrefsSizeHistogram.assertExpected();
             if (i > 0) {
                 cachedRttHistogram.assertExpected();
             }
diff --git a/components/cronet/cronet_prefs_manager.cc b/components/cronet/cronet_prefs_manager.cc
index cc5ed452..ae1e0667 100644
--- a/components/cronet/cronet_prefs_manager.cc
+++ b/components/cronet/cronet_prefs_manager.cc
@@ -182,7 +182,6 @@
 
   base::Value::Dict GetDictionaryValue() override {
     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    UMA_HISTOGRAM_EXACT_LINEAR("NQE.Prefs.ReadCount", 1, 2);
     return pref_service_->GetDict(kNetworkQualitiesPref).Clone();
   }
 
@@ -190,7 +189,6 @@
   // Schedules the writing of the lossy prefs.
   void SchedulePendingLossyWrites() {
     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    UMA_HISTOGRAM_EXACT_LINEAR("NQE.Prefs.WriteCount", 1, 2);
     pref_service_->SchedulePendingLossyWrites();
     lossy_prefs_writing_task_posted_ = false;
   }
diff --git a/components/feed/feed_feature_list.cc b/components/feed/feed_feature_list.cc
index c0739ea..bc09469 100644
--- a/components/feed/feed_feature_list.cc
+++ b/components/feed/feed_feature_list.cc
@@ -25,10 +25,6 @@
              "InterestFeedV2",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
-BASE_FEATURE(kInterestFeedV2Autoplay,
-             "InterestFeedV2Autoplay",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 BASE_FEATURE(kInterestFeedV2Hearts,
              "InterestFeedV2Hearts",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/components/feed/feed_feature_list.h b/components/feed/feed_feature_list.h
index adfadf1..3c4583ff 100644
--- a/components/feed/feed_feature_list.h
+++ b/components/feed/feed_feature_list.h
@@ -18,7 +18,6 @@
 namespace feed {
 
 BASE_DECLARE_FEATURE(kInterestFeedV2);
-BASE_DECLARE_FEATURE(kInterestFeedV2Autoplay);
 BASE_DECLARE_FEATURE(kInterestFeedV2Hearts);
 BASE_DECLARE_FEATURE(kInterestFeedV2Scrolling);
 
diff --git a/components/invalidation/impl/BUILD.gn b/components/invalidation/impl/BUILD.gn
index 98ab724..ebd820a 100644
--- a/components/invalidation/impl/BUILD.gn
+++ b/components/invalidation/impl/BUILD.gn
@@ -25,8 +25,6 @@
     "fcm_invalidation_listener.h",
     "fcm_invalidation_service.cc",
     "fcm_invalidation_service.h",
-    "fcm_invalidation_service_base.cc",
-    "fcm_invalidation_service_base.h",
     "fcm_network_handler.cc",
     "fcm_network_handler.h",
     "fcm_sync_network_channel.cc",
diff --git a/components/invalidation/impl/fcm_invalidation_service.cc b/components/invalidation/impl/fcm_invalidation_service.cc
index 501b01f..2096737 100644
--- a/components/invalidation/impl/fcm_invalidation_service.cc
+++ b/components/invalidation/impl/fcm_invalidation_service.cc
@@ -1,17 +1,27 @@
-// Copyright 2018 The Chromium Authors
+// Copyright 2019 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "components/invalidation/impl/fcm_invalidation_service.h"
 
+#include <set>
+
 #include "base/command_line.h"
-#include "base/sequence_checker.h"
-#include "build/build_config.h"
+#include "base/functional/bind.h"
+#include "base/strings/strcat.h"
+#include "components/gcm_driver/instance_id/instance_id_driver.h"
+#include "components/invalidation/impl/fcm_network_handler.h"
+#include "components/invalidation/impl/invalidation_prefs.h"
+#include "components/invalidation/public/invalidator_state.h"
+#include "components/invalidation/public/topic_data.h"
 #include "components/prefs/scoped_user_pref_update.h"
 
 namespace invalidation {
-
+namespace {
+constexpr char kApplicationName[] = "com.google.chrome.fcm.invalidations";
 constexpr char kDisableFcmInvalidationsSwitch[] = "disable-fcm-invalidations";
+constexpr char kDeprecatedSyncInvalidationGCMSenderId[] = "8181035976";
+}  // namespace
 
 FCMInvalidationService::FCMInvalidationService(
     IdentityProvider* identity_provider,
@@ -22,16 +32,27 @@
     instance_id::InstanceIDDriver* instance_id_driver,
     PrefService* pref_service,
     const std::string& sender_id)
-    : FCMInvalidationServiceBase(fcm_network_handler_callback,
-                                 fcm_invalidation_listener_callback,
-                                 per_user_topic_subscription_manager_callback,
-                                 instance_id_driver,
-                                 pref_service,
-                                 sender_id),
-      identity_provider_(identity_provider) {}
+    : sender_id_(sender_id),
+      invalidator_registrar_(pref_service, sender_id_),
+      fcm_network_handler_callback_(std::move(fcm_network_handler_callback)),
+      fcm_invalidation_listener_callback_(
+          std::move(fcm_invalidation_listener_callback)),
+      per_user_topic_subscription_manager_callback_(
+          std::move(per_user_topic_subscription_manager_callback)),
+      instance_id_driver_(instance_id_driver),
+      pref_service_(pref_service),
+      identity_provider_(identity_provider) {
+  CHECK(!sender_id_.empty());
+}
 
 FCMInvalidationService::~FCMInvalidationService() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  invalidator_registrar_.UpdateInvalidatorState(INVALIDATOR_SHUTTING_DOWN);
+
+  if (IsStarted()) {
+    StopInvalidator();
+  }
+
   identity_provider_->RemoveObserver(this);
 }
 
@@ -45,6 +66,73 @@
   identity_provider_->AddObserver(this);
 }
 
+// static
+void FCMInvalidationService::RegisterPrefs(PrefRegistrySimple* registry) {
+  registry->RegisterDictionaryPref(prefs::kInvalidationClientIDCache);
+}
+
+// static
+void FCMInvalidationService::ClearDeprecatedPrefs(PrefService* prefs) {
+  if (prefs->HasPrefPath(prefs::kInvalidationClientIDCache)) {
+    ScopedDictPrefUpdate update(prefs, prefs::kInvalidationClientIDCache);
+    update->Remove(kDeprecatedSyncInvalidationGCMSenderId);
+  }
+}
+
+void FCMInvalidationService::AddObserver(InvalidationHandler* handler) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DVLOG(2) << "Registering an invalidation handler";
+  invalidator_registrar_.AddObserver(handler);
+}
+
+bool FCMInvalidationService::HasObserver(
+    const InvalidationHandler* handler) const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  return invalidator_registrar_.HasObserver(handler);
+}
+
+bool FCMInvalidationService::UpdateInterestedTopics(
+    InvalidationHandler* handler,
+    const TopicSet& legacy_topic_set) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  update_was_requested_ = true;
+  DVLOG(2) << "Subscribing to topics: " << legacy_topic_set.size();
+  std::set<TopicData> topic_set;
+  for (const auto& topic_name : legacy_topic_set) {
+    topic_set.insert(TopicData(topic_name, handler->IsPublicTopic(topic_name)));
+  }
+  // TODO(crbug.com/1054404): UpdateRegisteredTopics() should be renamed to
+  // clarify that it actually updates whether topics need subscription (aka
+  // interested).
+  if (!invalidator_registrar_.UpdateRegisteredTopics(handler, topic_set)) {
+    return false;
+  }
+  DoUpdateSubscribedTopicsIfNeeded();
+  return true;
+}
+
+void FCMInvalidationService::RemoveObserver(
+    const InvalidationHandler* handler) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DVLOG(2) << "Unregistering";
+  invalidator_registrar_.RemoveObserver(handler);
+}
+
+InvalidatorState FCMInvalidationService::GetInvalidatorState() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (invalidation_listener_) {
+    DVLOG(2) << "GetInvalidatorState returning "
+             << invalidator_registrar_.GetInvalidatorState();
+    return invalidator_registrar_.GetInvalidatorState();
+  }
+  DVLOG(2) << "Invalidator currently stopped";
+  return STOPPED;
+}
+
+std::string FCMInvalidationService::GetInvalidatorClientId() const {
+  return client_id_;
+}
+
 void FCMInvalidationService::OnActiveAccountLogin() {
   if (IsStarted()) {
     return;
@@ -66,6 +154,18 @@
   }
 }
 
+void FCMInvalidationService::OnInvalidate(const Invalidation& invalidation) {
+  invalidator_registrar_.DispatchInvalidationToHandlers(invalidation);
+}
+
+void FCMInvalidationService::OnInvalidatorStateChange(InvalidatorState state) {
+  invalidator_registrar_.UpdateInvalidatorState(state);
+}
+
+bool FCMInvalidationService::IsStarted() const {
+  return invalidation_listener_ != nullptr;
+}
+
 bool FCMInvalidationService::IsReadyToStart() {
   base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
   if (cmd_line->HasSwitch(kDisableFcmInvalidationsSwitch)) {
@@ -93,4 +193,113 @@
   return true;
 }
 
+void FCMInvalidationService::StartInvalidator() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(!invalidation_listener_);
+
+  auto network =
+      fcm_network_handler_callback_.Run(sender_id_, GetApplicationName());
+  // The order of calls is important. Do not change.
+  // We should start listening before requesting the id, because
+  // valid id is only generated, once there is an app handler
+  // for the app. StartListening registers the app handler.
+  // We should create InvalidationListener first, because it registers the
+  // handler for the incoming messages, which is crucial on Android, because on
+  // the startup cached messages might exists.
+  invalidation_listener_ =
+      fcm_invalidation_listener_callback_.Run(std::move(network));
+  auto subscription_manager =
+      per_user_topic_subscription_manager_callback_.Run(sender_id_);
+  invalidation_listener_->Start(this, std::move(subscription_manager));
+
+  PopulateClientID();
+  DoUpdateSubscribedTopicsIfNeeded();
+}
+
+void FCMInvalidationService::StopInvalidator() {
+  DCHECK(invalidation_listener_);
+  invalidation_listener_.reset();
+}
+
+void FCMInvalidationService::StopInvalidatorPermanently() {
+  // Reset the client ID (aka InstanceID) *before* stopping, so that
+  // FCMInvalidationListener gets notified about the cleared ID (the listener
+  // gets destroyed during StopInvalidator()).
+  if (!client_id_.empty()) {
+    ResetClientID();
+  }
+
+  StopInvalidator();
+}
+
+void FCMInvalidationService::PopulateClientID() {
+  // Retrieve any client ID (aka Instance ID) from a previous run, which was
+  // cached in prefs.
+  const std::string* client_id_pref =
+      pref_service_->GetDict(prefs::kInvalidationClientIDCache)
+          .FindString(sender_id_);
+  client_id_ = client_id_pref ? *client_id_pref : "";
+
+  // Also retrieve a fresh (or validated) client ID. If the |client_id_| just
+  // retrieved from prefs is non-empty, then the fresh/validated one will
+  // typically be equal to it, but it's not completely guaranteed. OTOH, if
+  // |client_id_| is empty, i.e. we didn't have one previously, then this will
+  // generate/retrieve a new one.
+  instance_id::InstanceID* instance_id =
+      instance_id_driver_->GetInstanceID(GetApplicationName());
+  instance_id->GetID(base::BindOnce(
+      &FCMInvalidationService::OnInstanceIDReceived, base::Unretained(this)));
+}
+
+void FCMInvalidationService::ResetClientID() {
+  instance_id::InstanceID* instance_id =
+      instance_id_driver_->GetInstanceID(GetApplicationName());
+  instance_id->DeleteID(
+      base::BindOnce(&FCMInvalidationService::OnDeleteInstanceIDCompleted,
+                     base::Unretained(this)));
+
+  // Immediately clear our cached values (before we get confirmation of the
+  // deletion), since they shouldn't be used anymore. Lower layers are the
+  // source of truth, and are responsible for ensuring that the deletion
+  // actually happens.
+  client_id_.clear();
+  ScopedDictPrefUpdate update(pref_service_, prefs::kInvalidationClientIDCache);
+  update->Remove(sender_id_);
+
+  // This will also delete all Instance ID *tokens*; we need to let the
+  // FCMInvalidationListener know.
+  if (invalidation_listener_) {
+    invalidation_listener_->ClearInstanceIDToken();
+  }
+}
+
+void FCMInvalidationService::OnInstanceIDReceived(
+    const std::string& instance_id) {
+  if (client_id_ != instance_id) {
+    client_id_ = instance_id;
+    ScopedDictPrefUpdate update(pref_service_,
+                                prefs::kInvalidationClientIDCache);
+    update->Set(sender_id_, instance_id);
+  }
+}
+
+void FCMInvalidationService::OnDeleteInstanceIDCompleted(
+    instance_id::InstanceID::Result) {
+  // Note: |client_id_| and the pref were already cleared when we initiated the
+  // deletion.
+}
+
+void FCMInvalidationService::DoUpdateSubscribedTopicsIfNeeded() {
+  if (!invalidation_listener_ || !update_was_requested_) {
+    return;
+  }
+  auto subscribed_topics = invalidator_registrar_.GetAllSubscribedTopics();
+  invalidation_listener_->UpdateInterestedTopics(subscribed_topics);
+  update_was_requested_ = false;
+}
+
+const std::string FCMInvalidationService::GetApplicationName() {
+  return base::StrCat({kApplicationName, "-", sender_id_});
+}
+
 }  // namespace invalidation
diff --git a/components/invalidation/impl/fcm_invalidation_service.h b/components/invalidation/impl/fcm_invalidation_service.h
index bb17ef1d..ed199c8b 100644
--- a/components/invalidation/impl/fcm_invalidation_service.h
+++ b/components/invalidation/impl/fcm_invalidation_service.h
@@ -1,22 +1,51 @@
-// Copyright 2018 The Chromium Authors
+// Copyright 2019 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef COMPONENTS_INVALIDATION_IMPL_FCM_INVALIDATION_SERVICE_H_
 #define COMPONENTS_INVALIDATION_IMPL_FCM_INVALIDATION_SERVICE_H_
 
+#include <memory>
+#include <string>
+
+#include "base/functional/callback.h"
 #include "base/memory/raw_ptr.h"
 #include "base/sequence_checker.h"
-#include "components/invalidation/impl/fcm_invalidation_service_base.h"
-#include "components/invalidation/public/identity_provider.h"
+#include "components/gcm_driver/instance_id/instance_id.h"
+#include "components/invalidation/impl/fcm_invalidation_listener.h"
+#include "components/invalidation/impl/invalidator_registrar_with_memory.h"
+#include "components/invalidation/public/invalidation_handler.h"
+#include "components/invalidation/public/invalidation_service.h"
+
+class PrefService;
+class PrefRegistrySimple;
+
+namespace instance_id {
+class InstanceIDDriver;
+}
 
 namespace invalidation {
 
-// This concrete implementation of FCMInvalidationServiceBase starts the
-// invalidation service machinery once an account is signed in and conversely
-// stops it when the account is signed out.
-class FCMInvalidationService : public FCMInvalidationServiceBase,
-                               public IdentityProvider::Observer {
+class FCMNetworkHandler;
+class PerUserTopicSubscriptionManager;
+
+using FCMNetworkHandlerCallback =
+    base::RepeatingCallback<std::unique_ptr<FCMNetworkHandler>(
+        const std::string& sender_id,
+        const std::string& app_id)>;
+
+using PerUserTopicSubscriptionManagerCallback =
+    base::RepeatingCallback<std::unique_ptr<PerUserTopicSubscriptionManager>(
+        const std::string& project_id)>;
+
+using FCMInvalidationListenerCallback =
+    base::RepeatingCallback<std::unique_ptr<FCMInvalidationListener>(
+        std::unique_ptr<FCMSyncNetworkChannel>)>;
+
+// The InvalidationService wraps the C++ Invalidation Client (FCM) library.
+class FCMInvalidationService : public InvalidationService,
+                               public IdentityProvider::Observer,
+                               public FCMInvalidationListener::Delegate {
  public:
   FCMInvalidationService(
       IdentityProvider* identity_provider,
@@ -26,25 +55,83 @@
           per_user_topic_subscription_manager_callback,
       instance_id::InstanceIDDriver* instance_id_driver,
       PrefService* pref_service,
-      const std::string& sender_id = {});
+      const std::string& sender_id);
   FCMInvalidationService(const FCMInvalidationService& other) = delete;
   FCMInvalidationService& operator=(const FCMInvalidationService& other) =
       delete;
   ~FCMInvalidationService() override;
 
-  void Init() override;
+  void Init();
+
+  static void RegisterPrefs(PrefRegistrySimple* registry);
+  static void ClearDeprecatedPrefs(PrefService* prefs);
+
+  // InvalidationService implementation.
+  // It is an error to have registered handlers when the service is destroyed.
+  void AddObserver(InvalidationHandler* handler) override;
+  bool HasObserver(const InvalidationHandler* handler) const override;
+  bool UpdateInterestedTopics(InvalidationHandler* handler,
+                              const TopicSet& topics) override;
+  void RemoveObserver(const InvalidationHandler* handler) override;
+  InvalidatorState GetInvalidatorState() const override;
+  std::string GetInvalidatorClientId() const override;
 
   // IdentityProvider::Observer implementation.
   void OnActiveAccountRefreshTokenUpdated() override;
   void OnActiveAccountLogin() override;
   void OnActiveAccountLogout() override;
 
- protected:
-  friend class FCMInvalidationServiceTest;
+  // FCMInvalidationListener::Delegate implementation.
+  void OnInvalidate(const Invalidation& invalidation) override;
+  void OnInvalidatorStateChange(InvalidatorState state) override;
 
  private:
+  friend class FCMInvalidationServiceTest;
+
+  // Returns true if the service is currently started and able to receive
+  // invalidations.
+  bool IsStarted() const;
+  // Subclasses should be calling StartInvalidator and StopInvalidator when it
+  // is appropriate for their use case. This class will call StopInvalidator
+  // when it's destroyed if it's still started at that point.
+  // Start the invalidation service to start receiving invalidations.
+  void StartInvalidator();
+  // Stop the invalidation service to stop receiving invalidations. It's
+  // appropriate to call this when the service is expected to be started again
+  // with the same client ID (such as during shutdown).
+  void StopInvalidator();
+  // Stops the invalidation service to stop receiving invalidations. This also
+  // resets the Instance ID driver's client ID and clears the client ID cache.
+  void StopInvalidatorPermanently();
+
   bool IsReadyToStart();
 
+  void PopulateClientID();
+  void ResetClientID();
+  void OnInstanceIDReceived(const std::string& instance_id);
+  void OnDeleteInstanceIDCompleted(instance_id::InstanceID::Result);
+  void DoUpdateSubscribedTopicsIfNeeded();
+  const std::string GetApplicationName();
+
+  const std::string sender_id_;
+  InvalidatorRegistrarWithMemory invalidator_registrar_;
+
+  FCMNetworkHandlerCallback fcm_network_handler_callback_;
+  FCMInvalidationListenerCallback fcm_invalidation_listener_callback_;
+  PerUserTopicSubscriptionManagerCallback
+      per_user_topic_subscription_manager_callback_;
+
+  const raw_ptr<instance_id::InstanceIDDriver> instance_id_driver_;
+  // The invalidator client ID, aka instance ID.
+  std::string client_id_;
+
+  const raw_ptr<PrefService> pref_service_;
+
+  bool update_was_requested_ = false;
+
+  // The invalidation listener.
+  std::unique_ptr<FCMInvalidationListener> invalidation_listener_;
+
   const raw_ptr<IdentityProvider> identity_provider_;
 
   SEQUENCE_CHECKER(sequence_checker_);
diff --git a/components/invalidation/impl/fcm_invalidation_service_base.cc b/components/invalidation/impl/fcm_invalidation_service_base.cc
deleted file mode 100644
index b55f3c0a..0000000
--- a/components/invalidation/impl/fcm_invalidation_service_base.cc
+++ /dev/null
@@ -1,251 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/invalidation/impl/fcm_invalidation_service_base.h"
-
-#include <memory>
-
-#include "base/functional/bind.h"
-#include "base/i18n/time_formatting.h"
-#include "base/strings/strcat.h"
-#include "components/gcm_driver/instance_id/instance_id_driver.h"
-#include "components/invalidation/impl/fcm_network_handler.h"
-#include "components/invalidation/impl/invalidation_prefs.h"
-#include "components/invalidation/public/invalidator_state.h"
-#include "components/invalidation/public/topic_data.h"
-#include "components/prefs/scoped_user_pref_update.h"
-
-namespace invalidation {
-namespace {
-const char kApplicationName[] = "com.google.chrome.fcm.invalidations";
-constexpr char kDeprecatedSyncInvalidationGCMSenderId[] = "8181035976";
-}  // namespace
-
-FCMInvalidationServiceBase::FCMInvalidationServiceBase(
-    FCMNetworkHandlerCallback fcm_network_handler_callback,
-    FCMInvalidationListenerCallback fcm_invalidation_listener_callback,
-    PerUserTopicSubscriptionManagerCallback
-        per_user_topic_subscription_manager_callback,
-    instance_id::InstanceIDDriver* instance_id_driver,
-    PrefService* pref_service,
-    const std::string& sender_id)
-    : sender_id_(sender_id),
-      invalidator_registrar_(pref_service, sender_id_),
-      fcm_network_handler_callback_(std::move(fcm_network_handler_callback)),
-      fcm_invalidation_listener_callback_(
-          std::move(fcm_invalidation_listener_callback)),
-      per_user_topic_subscription_manager_callback_(
-          std::move(per_user_topic_subscription_manager_callback)),
-      instance_id_driver_(instance_id_driver),
-      pref_service_(pref_service) {
-  CHECK(!sender_id_.empty());
-}
-
-FCMInvalidationServiceBase::~FCMInvalidationServiceBase() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  invalidator_registrar_.UpdateInvalidatorState(INVALIDATOR_SHUTTING_DOWN);
-
-  if (IsStarted()) {
-    StopInvalidator();
-  }
-}
-
-// static
-void FCMInvalidationServiceBase::RegisterPrefs(PrefRegistrySimple* registry) {
-  registry->RegisterDictionaryPref(prefs::kInvalidationClientIDCache);
-}
-
-// static
-void FCMInvalidationServiceBase::ClearDeprecatedPrefs(PrefService* prefs) {
-  if (prefs->HasPrefPath(prefs::kInvalidationClientIDCache)) {
-    ScopedDictPrefUpdate update(prefs, prefs::kInvalidationClientIDCache);
-    update->Remove(kDeprecatedSyncInvalidationGCMSenderId);
-  }
-}
-
-void FCMInvalidationServiceBase::AddObserver(InvalidationHandler* handler) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DVLOG(2) << "Registering an invalidation handler";
-  invalidator_registrar_.AddObserver(handler);
-}
-
-bool FCMInvalidationServiceBase::HasObserver(
-    const InvalidationHandler* handler) const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  return invalidator_registrar_.HasObserver(handler);
-}
-
-bool FCMInvalidationServiceBase::UpdateInterestedTopics(
-    InvalidationHandler* handler,
-    const TopicSet& legacy_topic_set) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  update_was_requested_ = true;
-  DVLOG(2) << "Subscribing to topics: " << legacy_topic_set.size();
-  std::set<TopicData> topic_set;
-  for (const auto& topic_name : legacy_topic_set) {
-    topic_set.insert(TopicData(topic_name, handler->IsPublicTopic(topic_name)));
-  }
-  // TODO(crbug.com/1054404): UpdateRegisteredTopics() should be renamed to
-  // clarify that it actually updates whether topics need subscription (aka
-  // interested).
-  if (!invalidator_registrar_.UpdateRegisteredTopics(handler, topic_set)) {
-    return false;
-  }
-  DoUpdateSubscribedTopicsIfNeeded();
-  return true;
-}
-
-void FCMInvalidationServiceBase::RemoveObserver(
-    const InvalidationHandler* handler) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DVLOG(2) << "Unregistering";
-  invalidator_registrar_.RemoveObserver(handler);
-}
-
-InvalidatorState FCMInvalidationServiceBase::GetInvalidatorState() const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (invalidation_listener_) {
-    DVLOG(2) << "GetInvalidatorState returning "
-             << invalidator_registrar_.GetInvalidatorState();
-    return invalidator_registrar_.GetInvalidatorState();
-  }
-  DVLOG(2) << "Invalidator currently stopped";
-  return STOPPED;
-}
-
-std::string FCMInvalidationServiceBase::GetInvalidatorClientId() const {
-  return client_id_;
-}
-
-void FCMInvalidationServiceBase::OnInvalidate(
-    const Invalidation& invalidation) {
-  invalidator_registrar_.DispatchInvalidationToHandlers(invalidation);
-}
-
-void FCMInvalidationServiceBase::OnInvalidatorStateChange(
-    InvalidatorState state) {
-  invalidator_registrar_.UpdateInvalidatorState(state);
-}
-
-bool FCMInvalidationServiceBase::IsStarted() const {
-  return invalidation_listener_ != nullptr;
-}
-
-void FCMInvalidationServiceBase::StartInvalidator() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(!invalidation_listener_);
-
-  diagnostic_info_.service_was_started = base::Time::Now();
-  auto network =
-      fcm_network_handler_callback_.Run(sender_id_, GetApplicationName());
-  // The order of calls is important. Do not change.
-  // We should start listening before requesting the id, because
-  // valid id is only generated, once there is an app handler
-  // for the app. StartListening registers the app handler.
-  // We should create InvalidationListener first, because it registers the
-  // handler for the incoming messages, which is crucial on Android, because on
-  // the startup cached messages might exists.
-  invalidation_listener_ =
-      fcm_invalidation_listener_callback_.Run(std::move(network));
-  auto subscription_manager =
-      per_user_topic_subscription_manager_callback_.Run(sender_id_);
-  invalidation_listener_->Start(this, std::move(subscription_manager));
-
-  PopulateClientID();
-  DoUpdateSubscribedTopicsIfNeeded();
-}
-
-void FCMInvalidationServiceBase::StopInvalidator() {
-  DCHECK(invalidation_listener_);
-  diagnostic_info_.service_was_stopped = base::Time::Now();
-  invalidation_listener_.reset();
-}
-
-void FCMInvalidationServiceBase::StopInvalidatorPermanently() {
-  // Reset the client ID (aka InstanceID) *before* stopping, so that
-  // FCMInvalidationListener gets notified about the cleared ID (the listener
-  // gets destroyed during StopInvalidator()).
-  if (!client_id_.empty()) {
-    ResetClientID();
-  }
-
-  StopInvalidator();
-}
-
-void FCMInvalidationServiceBase::PopulateClientID() {
-  diagnostic_info_.instance_id_requested = base::Time::Now();
-
-  // Retrieve any client ID (aka Instance ID) from a previous run, which was
-  // cached in prefs.
-  const std::string* client_id_pref =
-      pref_service_->GetDict(prefs::kInvalidationClientIDCache)
-          .FindString(sender_id_);
-  client_id_ = client_id_pref ? *client_id_pref : "";
-
-  // Also retrieve a fresh (or validated) client ID. If the |client_id_| just
-  // retrieved from prefs is non-empty, then the fresh/validated one will
-  // typically be equal to it, but it's not completely guaranteed. OTOH, if
-  // |client_id_| is empty, i.e. we didn't have one previously, then this will
-  // generate/retrieve a new one.
-  instance_id::InstanceID* instance_id =
-      instance_id_driver_->GetInstanceID(GetApplicationName());
-  instance_id->GetID(
-      base::BindOnce(&FCMInvalidationServiceBase::OnInstanceIDReceived,
-                     base::Unretained(this)));
-}
-
-void FCMInvalidationServiceBase::ResetClientID() {
-  instance_id::InstanceID* instance_id =
-      instance_id_driver_->GetInstanceID(GetApplicationName());
-  instance_id->DeleteID(
-      base::BindOnce(&FCMInvalidationServiceBase::OnDeleteInstanceIDCompleted,
-                     base::Unretained(this)));
-
-  // Immediately clear our cached values (before we get confirmation of the
-  // deletion), since they shouldn't be used anymore. Lower layers are the
-  // source of truth, and are responsible for ensuring that the deletion
-  // actually happens.
-  client_id_.clear();
-  ScopedDictPrefUpdate update(pref_service_, prefs::kInvalidationClientIDCache);
-  update->Remove(sender_id_);
-
-  // This will also delete all Instance ID *tokens*; we need to let the
-  // FCMInvalidationListener know.
-  if (invalidation_listener_) {
-    invalidation_listener_->ClearInstanceIDToken();
-  }
-}
-
-void FCMInvalidationServiceBase::OnInstanceIDReceived(
-    const std::string& instance_id) {
-  diagnostic_info_.instance_id_received = base::Time::Now();
-  if (client_id_ != instance_id) {
-    client_id_ = instance_id;
-    ScopedDictPrefUpdate update(pref_service_,
-                                prefs::kInvalidationClientIDCache);
-    update->Set(sender_id_, instance_id);
-  }
-}
-
-void FCMInvalidationServiceBase::OnDeleteInstanceIDCompleted(
-    instance_id::InstanceID::Result) {
-  // Note: |client_id_| and the pref were already cleared when we initiated the
-  // deletion.
-  diagnostic_info_.instance_id_cleared = base::Time::Now();
-}
-
-void FCMInvalidationServiceBase::DoUpdateSubscribedTopicsIfNeeded() {
-  if (!invalidation_listener_ || !update_was_requested_) {
-    return;
-  }
-  auto subscribed_topics = invalidator_registrar_.GetAllSubscribedTopics();
-  invalidation_listener_->UpdateInterestedTopics(subscribed_topics);
-  update_was_requested_ = false;
-}
-
-const std::string FCMInvalidationServiceBase::GetApplicationName() {
-  return base::StrCat({kApplicationName, "-", sender_id_});
-}
-
-}  // namespace invalidation
diff --git a/components/invalidation/impl/fcm_invalidation_service_base.h b/components/invalidation/impl/fcm_invalidation_service_base.h
deleted file mode 100644
index 4f7bbde..0000000
--- a/components/invalidation/impl/fcm_invalidation_service_base.h
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_INVALIDATION_IMPL_FCM_INVALIDATION_SERVICE_BASE_H_
-#define COMPONENTS_INVALIDATION_IMPL_FCM_INVALIDATION_SERVICE_BASE_H_
-
-#include "base/memory/raw_ptr.h"
-#include "base/sequence_checker.h"
-#include "base/time/time.h"
-#include "components/gcm_driver/instance_id/instance_id.h"
-#include "components/invalidation/impl/fcm_invalidation_listener.h"
-#include "components/invalidation/impl/invalidator_registrar_with_memory.h"
-#include "components/invalidation/public/invalidation_handler.h"
-#include "components/invalidation/public/invalidation_service.h"
-
-class PrefService;
-class PrefRegistrySimple;
-
-namespace instance_id {
-class InstanceIDDriver;
-}
-
-namespace invalidation {
-
-class FCMNetworkHandler;
-class PerUserTopicSubscriptionManager;
-
-using FCMNetworkHandlerCallback =
-    base::RepeatingCallback<std::unique_ptr<FCMNetworkHandler>(
-        const std::string& sender_id,
-        const std::string& app_id)>;
-
-using PerUserTopicSubscriptionManagerCallback =
-    base::RepeatingCallback<std::unique_ptr<PerUserTopicSubscriptionManager>(
-        const std::string& project_id)>;
-
-using FCMInvalidationListenerCallback =
-    base::RepeatingCallback<std::unique_ptr<FCMInvalidationListener>(
-        std::unique_ptr<FCMSyncNetworkChannel>)>;
-
-// This InvalidationService wraps the C++ Invalidation Client (FCM) library.
-// It provides invalidations for desktop platforms (Win, Mac, Linux).
-// Subclasses should implement Init to set up their initial state and call
-// StartInvalidator/StopInvalidator when they want to start/stop receiving
-// invalidations.
-class FCMInvalidationServiceBase : public InvalidationService,
-                                   public FCMInvalidationListener::Delegate {
- public:
-  FCMInvalidationServiceBase(
-      FCMNetworkHandlerCallback fcm_network_handler_callback,
-      FCMInvalidationListenerCallback fcm_invalidation_listener_callback,
-      PerUserTopicSubscriptionManagerCallback
-          per_user_topic_subscription_manager_callback,
-      instance_id::InstanceIDDriver* instance_id_driver,
-      PrefService* pref_service,
-      const std::string& sender_id);
-  FCMInvalidationServiceBase(const FCMInvalidationServiceBase& other) = delete;
-  FCMInvalidationServiceBase& operator=(
-      const FCMInvalidationServiceBase& other) = delete;
-  ~FCMInvalidationServiceBase() override;
-
-  virtual void Init() = 0;
-
-  static void RegisterPrefs(PrefRegistrySimple* registry);
-  static void ClearDeprecatedPrefs(PrefService* prefs);
-
-  // InvalidationService implementation.
-  // It is an error to have registered handlers when the service is destroyed.
-  void AddObserver(InvalidationHandler* handler) override;
-  bool HasObserver(const InvalidationHandler* handler) const override;
-  bool UpdateInterestedTopics(InvalidationHandler* handler,
-                              const TopicSet& topics) override;
-  void RemoveObserver(const InvalidationHandler* handler) override;
-  InvalidatorState GetInvalidatorState() const override;
-  std::string GetInvalidatorClientId() const override;
-
-  // FCMInvalidationListener::Delegate implementation.
-  void OnInvalidate(const Invalidation& invalidation) override;
-  void OnInvalidatorStateChange(InvalidatorState state) override;
-
- protected:
-  // Returns true if the service is currently started and able to receive
-  // invalidations.
-  bool IsStarted() const;
-  // Subclasses should be calling StartInvalidator and StopInvalidator when it
-  // is appropriate for their use case. This class will call StopInvalidator
-  // when it's destroyed if it's still started at that point.
-  // Start the invalidation service to start receiving invalidations.
-  void StartInvalidator();
-  // Stop the invalidation service to stop receiving invalidations. It's
-  // appropriate to call this when the service is expected to be started again
-  // with the same client ID (such as during shutdown).
-  void StopInvalidator();
-  // Stops the invalidation service to stop receiving invalidations. This also
-  // resets the Instance ID driver's client ID and clears the client ID cache.
-  void StopInvalidatorPermanently();
-
- private:
-  struct Diagnostics {
-    base::Time instance_id_requested;
-    base::Time instance_id_received;
-    base::Time instance_id_cleared;
-    base::Time service_was_stopped;
-    base::Time service_was_started;
-  };
-
-  void PopulateClientID();
-  void ResetClientID();
-  void OnInstanceIDReceived(const std::string& instance_id);
-  void OnDeleteInstanceIDCompleted(instance_id::InstanceID::Result);
-  void DoUpdateSubscribedTopicsIfNeeded();
-  const std::string GetApplicationName();
-
-  const std::string sender_id_;
-  InvalidatorRegistrarWithMemory invalidator_registrar_;
-
-  FCMNetworkHandlerCallback fcm_network_handler_callback_;
-  FCMInvalidationListenerCallback fcm_invalidation_listener_callback_;
-  PerUserTopicSubscriptionManagerCallback
-      per_user_topic_subscription_manager_callback_;
-
-  const raw_ptr<instance_id::InstanceIDDriver> instance_id_driver_;
-  // The invalidator client ID, aka instance ID.
-  std::string client_id_;
-
-  const raw_ptr<PrefService> pref_service_;
-
-  bool update_was_requested_ = false;
-  Diagnostics diagnostic_info_;
-
-  // The invalidation listener.
-  std::unique_ptr<FCMInvalidationListener> invalidation_listener_;
-
-  SEQUENCE_CHECKER(sequence_checker_);
-};
-
-}  // namespace invalidation
-
-#endif  // COMPONENTS_INVALIDATION_IMPL_FCM_INVALIDATION_SERVICE_BASE_H_
diff --git a/components/js_injection/common/BUILD.gn b/components/js_injection/common/BUILD.gn
index 2390df8..8c387df 100644
--- a/components/js_injection/common/BUILD.gn
+++ b/components/js_injection/common/BUILD.gn
@@ -54,11 +54,9 @@
 
 source_set("common") {
   public = [
-    "features.h",
     "origin_matcher.h",
   ]
   sources = [
-    "features.cc",
     "origin_matcher.cc",
     "origin_matcher_internal.cc",
     "origin_matcher_internal.h",
diff --git a/components/js_injection/common/features.cc b/components/js_injection/common/features.cc
deleted file mode 100644
index c60c364..0000000
--- a/components/js_injection/common/features.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/js_injection/common/features.h"
-
-namespace js_injection {
-
-BASE_DECLARE_FEATURE(kArrayBufferJsToBrowser);
-
-BASE_FEATURE(kArrayBufferJsToBrowser,
-             "JsInjectionArrayBufferJsToBrowser",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
-bool IsJsToBrowserArrayBufferSupported() {
-  return base::FeatureList::IsEnabled(kArrayBufferJsToBrowser);
-}
-
-}  // namespace js_injection
diff --git a/components/js_injection/common/features.h b/components/js_injection/common/features.h
deleted file mode 100644
index 74ddffa10..0000000
--- a/components/js_injection/common/features.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_JS_INJECTION_COMMON_FEATURES_H_
-#define COMPONENTS_JS_INJECTION_COMMON_FEATURES_H_
-
-#include "base/feature_list.h"
-
-namespace js_injection {
-
-// Feature to enable ArrayBuffer support in JS to Browser messaging.
-BASE_DECLARE_FEATURE(kArrayBufferJsToBrowser);
-
-bool IsJsToBrowserArrayBufferSupported();
-
-}  // namespace js_injection
-
-#endif  // COMPONENTS_JS_INJECTION_COMMON_FEATURES_H_
diff --git a/components/js_injection/renderer/js_binding.cc b/components/js_injection/renderer/js_binding.cc
index e8e32136..67955325 100644
--- a/components/js_injection/renderer/js_binding.cc
+++ b/components/js_injection/renderer/js_binding.cc
@@ -13,7 +13,6 @@
 #include "base/functional/overloaded.h"
 #include "base/ranges/algorithm.h"
 #include "base/strings/string_util.h"
-#include "components/js_injection/common/features.h"
 #include "components/js_injection/common/interfaces.mojom-forward.h"
 #include "components/js_injection/renderer/js_communication.h"
 #include "content/public/renderer/render_frame.h"
@@ -219,8 +218,7 @@
     gin::Converter<std::u16string>::FromV8(args->isolate(), js_payload,
                                            &string);
     message_payload = std::move(string);
-  } else if (IsJsToBrowserArrayBufferSupported() &&
-             js_payload->IsArrayBuffer()) {
+  } else if (js_payload->IsArrayBuffer()) {
     v8::Local<v8::ArrayBuffer> array_buffer = js_payload.As<v8::ArrayBuffer>();
     message_payload = std::make_unique<V8ArrayBufferPayload>(array_buffer);
   } else {
diff --git a/components/lens/lens_features.cc b/components/lens/lens_features.cc
index eee71ba..82733849 100644
--- a/components/lens/lens_features.cc
+++ b/components/lens/lens_features.cc
@@ -42,10 +42,6 @@
              "LensRegionSearchStaticPage",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-BASE_FEATURE(kLensImageFormatOptimizations,
-             "LensImageFormatOptimizations",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 BASE_FEATURE(kEnableContextMenuInLensSidePanel,
              "EnableContextMenuInLensSidePanel",
              base::FEATURE_ENABLED_BY_DEFAULT);
@@ -98,18 +94,6 @@
 const base::FeatureParam<bool> kEnableLensFullscreenSearch{
     &kLensSearchOptimizations, "enable-lens-fullscreen-search", false};
 
-const base::FeatureParam<int> kEncodingQualityJpeg{
-    &kLensImageFormatOptimizations, "encoding-quality-jpeg", 40};
-
-const base::FeatureParam<int> kEncodingQualityWebp{
-    &kLensImageFormatOptimizations, "encoding-quality-webp", 45};
-
-const base::FeatureParam<bool> kUseWebpForImageSearch{
-    &kLensImageFormatOptimizations, "use-webp-for-image-search", false};
-
-const base::FeatureParam<bool> kUseJpegForImageSearch{
-    &kLensImageFormatOptimizations, "use-jpeg-for-image-search", true};
-
 bool GetEnableLatencyLogging() {
   return base::FeatureList::IsEnabled(kEnableLatencyLogging) &&
          base::FeatureList::IsEnabled(kLensStandalone);
@@ -173,24 +157,6 @@
   return base::FeatureList::IsEnabled(kLensRegionSearchStaticPage);
 }
 
-int GetEncodingQualityJpeg() {
-  return kEncodingQualityJpeg.Get();
-}
-
-int GetEncodingQualityWebp() {
-  return kEncodingQualityWebp.Get();
-}
-
-bool IsWebpForImageSearchEnabled() {
-  return base::FeatureList::IsEnabled(kLensImageFormatOptimizations) &&
-         kUseWebpForImageSearch.Get();
-}
-
-bool IsJpegForImageSearchEnabled() {
-  return base::FeatureList::IsEnabled(kLensImageFormatOptimizations) &&
-         kUseJpegForImageSearch.Get();
-}
-
 bool GetEnableContextMenuInLensSidePanel() {
   return base::FeatureList::IsEnabled(kEnableContextMenuInLensSidePanel);
 }
diff --git a/components/lens/lens_features.h b/components/lens/lens_features.h
index 6336ceb6..ffbdb96 100644
--- a/components/lens/lens_features.h
+++ b/components/lens/lens_features.h
@@ -48,10 +48,6 @@
 COMPONENT_EXPORT(LENS_FEATURES)
 BASE_DECLARE_FEATURE(kLensRegionSearchStaticPage);
 
-// Enables using more optimized image formats for Lens requests.
-COMPONENT_EXPORT(LENS_FEATURES)
-BASE_DECLARE_FEATURE(kLensImageFormatOptimizations);
-
 // Enables the context menu in the Lens side panel.
 COMPONENT_EXPORT(LENS_FEATURES)
 BASE_DECLARE_FEATURE(EnableContextMenuInLensSidePanel);
@@ -97,26 +93,6 @@
 COMPONENT_EXPORT(LENS_FEATURES)
 extern const base::FeatureParam<bool> kEnableFullscreenSearch;
 
-// Enables encoding to WebP for region search queries. This param takes
-// precedence over kUseJpegForImageSearch.
-COMPONENT_EXPORT(LENS_FEATURES)
-extern const base::FeatureParam<bool> kUseWebpForImageSearch;
-
-// Enables encoding to JPEG for region search queries. This param does
-// nothing if kUseWebpForImageSearch is enabled.
-COMPONENT_EXPORT(LENS_FEATURES)
-extern const base::FeatureParam<bool> kUseJpegForImageSearch;
-
-// Value in range 0-100 that dictates the encoding quality for jpeg
-// format.
-COMPONENT_EXPORT(LENS_FEATURES)
-extern const base::FeatureParam<int> kEncodingQualityJpeg;
-
-// Value in range 0-100 that dictates the encoding quality for webp
-// format.
-COMPONENT_EXPORT(LENS_FEATURES)
-extern const base::FeatureParam<int> kEncodingQualityWebp;
-
 // Enables Latency logging for the LensStandalone feature.
 COMPONENT_EXPORT(LENS_FEATURES)
 extern bool GetEnableLatencyLogging();
@@ -189,22 +165,6 @@
 COMPONENT_EXPORT(LENS_FEATURES)
 extern bool IsLensRegionSearchStaticPageEnabled();
 
-// Get the encoding quality for jpeg search queries.
-COMPONENT_EXPORT(LENS_FEATURES)
-extern int GetEncodingQualityJpeg();
-
-// Get the encoding quality for webp search queries.
-COMPONENT_EXPORT(LENS_FEATURES)
-extern int GetEncodingQualityWebp();
-
-// Returns whether to use WebP encoding for image search queries.
-COMPONENT_EXPORT(LENS_FEATURES)
-extern bool IsWebpForImageSearchEnabled();
-
-// Returns whether to use JPEG encoding for image search queries.
-COMPONENT_EXPORT(LENS_FEATURES)
-extern bool IsJpegForImageSearchEnabled();
-
 // Returns whether to enable the context menu in the Lens side panel.
 COMPONENT_EXPORT(LENS_FEATURES)
 extern bool GetEnableContextMenuInLensSidePanel();
diff --git a/components/offline_pages/core/offline_page_feature.cc b/components/offline_pages/core/offline_page_feature.cc
index 0fd9e4f..64b831c1 100644
--- a/components/offline_pages/core/offline_page_feature.cc
+++ b/components/offline_pages/core/offline_page_feature.cc
@@ -24,10 +24,6 @@
              "OfflinePagesCT",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
-BASE_FEATURE(kOfflinePagesLivePageSharingFeature,
-             "OfflinePagesLivePageSharing",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 BASE_FEATURE(kOfflinePagesDescriptiveFailStatusFeature,
              "OfflinePagesDescriptiveFailStatus",
              base::FEATURE_DISABLED_BY_DEFAULT);
@@ -50,10 +46,6 @@
   return base::FeatureList::IsEnabled(kOfflinePagesCTFeature);
 }
 
-bool IsOfflinePagesLivePageSharingEnabled() {
-  return base::FeatureList::IsEnabled(kOfflinePagesLivePageSharingFeature);
-}
-
 bool ShouldUseTestingSnapshotDelay() {
   base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
   return cl->HasSwitch(kOfflinePagesUseTestingSnapshotDelay);
diff --git a/components/offline_pages/core/offline_page_feature.h b/components/offline_pages/core/offline_page_feature.h
index d9715f8..a5818ec 100644
--- a/components/offline_pages/core/offline_page_feature.h
+++ b/components/offline_pages/core/offline_page_feature.h
@@ -11,7 +11,6 @@
 namespace offline_pages {
 
 BASE_DECLARE_FEATURE(kOfflinePagesCTFeature);
-BASE_DECLARE_FEATURE(kOfflinePagesLivePageSharingFeature);
 BASE_DECLARE_FEATURE(kBackgroundLoaderForDownloadsFeature);
 BASE_DECLARE_FEATURE(kOfflinePagesCTV2Feature);
 BASE_DECLARE_FEATURE(kOfflinePagesDescriptivePendingStatusFeature);
@@ -27,9 +26,6 @@
 // Returns true if offline CT features are enabled.  See crbug.com/620421.
 bool IsOfflinePagesCTEnabled();
 
-// Returns true if live page sharing of offline page is enabled.
-bool IsOfflinePagesLivePageSharingEnabled();
-
 // Returns true if a command line for test has been set that shortens the
 // snapshot delay.
 bool ShouldUseTestingSnapshotDelay();
diff --git a/components/optimization_guide/core/model_execution/model_execution_features.cc b/components/optimization_guide/core/model_execution/model_execution_features.cc
index 6d29683..20cfc12a 100644
--- a/components/optimization_guide/core/model_execution/model_execution_features.cc
+++ b/components/optimization_guide/core/model_execution/model_execution_features.cc
@@ -34,6 +34,7 @@
       return &kTabOrganizationSettingsVisibility;
     case proto::ModelExecutionFeature::MODEL_EXECUTION_FEATURE_WALLPAPER_SEARCH:
       return &kWallpaperSearchSettingsVisibility;
+    case proto::ModelExecutionFeature::MODEL_EXECUTION_FEATURE_TEST:
     case proto::ModelExecutionFeature::MODEL_EXECUTION_FEATURE_UNSPECIFIED:
       NOTREACHED();
       return nullptr;
@@ -51,6 +52,10 @@
         proto::ModelExecutionFeature::MODEL_EXECUTION_FEATURE_UNSPECIFIED) {
       continue;
     }
+    if (model_execution_feature ==
+        proto::ModelExecutionFeature::MODEL_EXECUTION_FEATURE_TEST) {
+      continue;
+    }
     const auto* feature =
         GetFeatureToUseToCheckSettingsVisibility(model_execution_feature);
     if (GetFieldTrialParamByFeatureAsBool(*feature, "allow_unsigned_user",
diff --git a/components/optimization_guide/core/model_execution/model_execution_features_controller.cc b/components/optimization_guide/core/model_execution/model_execution_features_controller.cc
index f8d4f60..758fe3f 100644
--- a/components/optimization_guide/core/model_execution/model_execution_features_controller.cc
+++ b/components/optimization_guide/core/model_execution/model_execution_features_controller.cc
@@ -18,6 +18,11 @@
 
 namespace {
 
+bool ShouldCheckSettingForFeature(proto::ModelExecutionFeature feature) {
+  return feature != proto::MODEL_EXECUTION_FEATURE_UNSPECIFIED &&
+         feature != proto::MODEL_EXECUTION_FEATURE_TEST;
+}
+
 enum class SettingsVisibilityResult {
   kUnknown = 0,
   // Not visible because user is not signed-in.
@@ -186,17 +191,14 @@
     proto::ModelExecutionFeature feature) const {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
-  switch (feature) {
-    case proto::ModelExecutionFeature::MODEL_EXECUTION_FEATURE_UNSPECIFIED:
-      NOTREACHED();
-      return prefs::FeatureOptInState::kNotInitialized;
-    default:
-      return static_cast<prefs::FeatureOptInState>(
-          browser_context_profile_service_->GetInteger(
-              prefs::GetSettingEnabledPrefName(feature)));
+  if (!ShouldCheckSettingForFeature(feature)) {
+    NOTREACHED();
+    return prefs::FeatureOptInState::kNotInitialized;
   }
-  NOTREACHED();
-  return prefs::FeatureOptInState::kNotInitialized;
+
+  return static_cast<prefs::FeatureOptInState>(
+      browser_context_profile_service_->GetInteger(
+          prefs::GetSettingEnabledPrefName(feature)));
 }
 
 ModelExecutionFeaturesController::UserValidityResult
@@ -338,10 +340,10 @@
   features_enabled_at_startup_.clear();
   for (int i = 0; i < proto::ModelExecutionFeature_ARRAYSIZE; ++i) {
     proto::ModelExecutionFeature feature = proto::ModelExecutionFeature(i);
-    if (feature ==
-        proto::ModelExecutionFeature::MODEL_EXECUTION_FEATURE_UNSPECIFIED) {
+    if (!ShouldCheckSettingForFeature(feature)) {
       continue;
     }
+
     bool is_enabled =
         GetPrefState(feature) == prefs::FeatureOptInState::kEnabled;
     base::UmaHistogramBoolean(
@@ -382,16 +384,14 @@
        i <= proto::ModelExecutionFeature_MAX; ++i) {
     proto::ModelExecutionFeature feature =
         static_cast<proto::ModelExecutionFeature>(i);
-    switch (feature) {
-      case proto::ModelExecutionFeature::MODEL_EXECUTION_FEATURE_UNSPECIFIED:
-        continue;
-      default:
-        if (GetCurrentUserValidityResult(feature) !=
-            ModelExecutionFeaturesController::UserValidityResult::kValid) {
-          browser_context_profile_service_->SetInteger(
-              optimization_guide::prefs::GetSettingEnabledPrefName(feature),
-              static_cast<int>(prefs::FeatureOptInState::kNotInitialized));
-        }
+    if (!ShouldCheckSettingForFeature(feature)) {
+      continue;
+    }
+    if (GetCurrentUserValidityResult(feature) !=
+        ModelExecutionFeaturesController::UserValidityResult::kValid) {
+      browser_context_profile_service_->SetInteger(
+          optimization_guide::prefs::GetSettingEnabledPrefName(feature),
+          static_cast<int>(prefs::FeatureOptInState::kNotInitialized));
     }
   }
 }
@@ -411,8 +411,7 @@
        i <= proto::ModelExecutionFeature_MAX; ++i) {
     proto::ModelExecutionFeature feature =
         static_cast<proto::ModelExecutionFeature>(i);
-    if (feature ==
-        proto::ModelExecutionFeature::MODEL_EXECUTION_FEATURE_UNSPECIFIED) {
+    if (!ShouldCheckSettingForFeature(feature)) {
       continue;
     }
 
@@ -446,8 +445,7 @@
        i <= proto::ModelExecutionFeature_MAX; ++i) {
     proto::ModelExecutionFeature feature =
         static_cast<proto::ModelExecutionFeature>(i);
-    if (feature ==
-        proto::ModelExecutionFeature::MODEL_EXECUTION_FEATURE_UNSPECIFIED) {
+    if (!ShouldCheckSettingForFeature(feature)) {
       continue;
     }
 
diff --git a/components/optimization_guide/core/model_execution/model_execution_manager.cc b/components/optimization_guide/core/model_execution/model_execution_manager.cc
index 8187078..02d05515 100644
--- a/components/optimization_guide/core/model_execution/model_execution_manager.cc
+++ b/components/optimization_guide/core/model_execution/model_execution_manager.cc
@@ -19,6 +19,7 @@
 #include "components/optimization_guide/core/model_util.h"
 #include "components/optimization_guide/core/optimization_guide_constants.h"
 #include "components/optimization_guide/core/optimization_guide_logger.h"
+#include "components/optimization_guide/core/optimization_guide_model_provider.h"
 #include "components/optimization_guide/core/optimization_guide_util.h"
 #include "components/optimization_guide/core/optimization_metadata.h"
 #include "components/optimization_guide/proto/common_types.pb.h"
@@ -97,6 +98,7 @@
     signin::IdentityManager* identity_manager,
     scoped_refptr<OnDeviceModelServiceController>
         on_device_model_service_controller,
+    OptimizationGuideModelProvider* model_provider,
     OptimizationGuideLogger* optimization_guide_logger)
     : optimization_guide_logger_(optimization_guide_logger),
       model_execution_service_url_(net::AppendOrReplaceQueryParameter(
@@ -105,10 +107,22 @@
           features::GetOptimizationGuideServiceAPIKey())),
       url_loader_factory_(url_loader_factory),
       identity_manager_(identity_manager),
+      model_provider_(model_provider),
       on_device_model_service_controller_(
-          std::move(on_device_model_service_controller)) {}
+          std::move(on_device_model_service_controller)) {
+  if (model_provider_ && features::ShouldDownloadTextSafetyClassifierModel()) {
+    model_provider_->AddObserverForOptimizationTargetModel(
+        proto::OptimizationTarget::OPTIMIZATION_TARGET_TEXT_SAFETY,
+        /*model_metadata=*/absl::nullopt, this);
+  }
+}
 
-ModelExecutionManager::~ModelExecutionManager() = default;
+ModelExecutionManager::~ModelExecutionManager() {
+  if (model_provider_ && features::ShouldDownloadTextSafetyClassifierModel()) {
+    model_provider_->RemoveObserverForOptimizationTargetModel(
+        proto::OptimizationTarget::OPTIMIZATION_TARGET_TEXT_SAFETY, this);
+  }
+}
 
 void ModelExecutionManager::ExecuteModelWithStreaming(
     proto::ModelExecutionFeature feature,
@@ -333,4 +347,19 @@
                           std::move(log_entry));
 }
 
+void ModelExecutionManager::OnModelUpdated(
+    proto::OptimizationTarget optimization_target,
+    base::optional_ref<const ModelInfo> model_info) {
+  if (optimization_target != proto::OPTIMIZATION_TARGET_TEXT_SAFETY) {
+    return;
+  }
+
+  if (!on_device_model_service_controller_) {
+    return;
+  }
+
+  // Pass model file to on-device service controller.
+  on_device_model_service_controller_->MaybeUpdateSafetyModel(model_info);
+}
+
 }  // namespace optimization_guide
diff --git a/components/optimization_guide/core/model_execution/model_execution_manager.h b/components/optimization_guide/core/model_execution/model_execution_manager.h
index 5f918eb..9552da8 100644
--- a/components/optimization_guide/core/model_execution/model_execution_manager.h
+++ b/components/optimization_guide/core/model_execution/model_execution_manager.h
@@ -14,6 +14,7 @@
 #include "base/sequence_checker.h"
 #include "components/optimization_guide/core/optimization_guide_features.h"
 #include "components/optimization_guide/core/optimization_guide_model_executor.h"
+#include "components/optimization_guide/core/optimization_target_model_observer.h"
 #include "components/optimization_guide/proto/model_execution.pb.h"
 #include "components/optimization_guide/proto/model_quality_service.pb.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
@@ -34,17 +35,19 @@
 
 class ModelExecutionFetcher;
 class OnDeviceModelServiceController;
+class OptimizationGuideModelProvider;
 
-class ModelExecutionManager {
+class ModelExecutionManager : public OptimizationTargetModelObserver {
  public:
   ModelExecutionManager(
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       signin::IdentityManager* identity_manager,
       scoped_refptr<OnDeviceModelServiceController>
           on_device_model_service_controller,
+      OptimizationGuideModelProvider* model_provider,
       OptimizationGuideLogger* optimization_guide_logger);
 
-  ~ModelExecutionManager();
+  ~ModelExecutionManager() override;
 
   ModelExecutionManager(const ModelExecutionManager&) = delete;
   ModelExecutionManager& operator=(const ModelExecutionManager&) = delete;
@@ -64,6 +67,10 @@
   std::unique_ptr<OptimizationGuideModelExecutor::Session> StartSession(
       proto::ModelExecutionFeature feature);
 
+  // OptimizationTargetModelObserver:
+  void OnModelUpdated(proto::OptimizationTarget target,
+                      base::optional_ref<const ModelInfo> model_info) override;
+
  private:
   // Called from SessionImpl (via ExecuteRemoteFn) when model execution happens
   // remotely.
@@ -98,6 +105,9 @@
   // incognito profiles.
   const raw_ptr<signin::IdentityManager> identity_manager_;
 
+  // The model provider to observe for updates to auxiliary models.
+  raw_ptr<OptimizationGuideModelProvider> model_provider_;
+
   // Controller for the on-device service.
   scoped_refptr<OnDeviceModelServiceController>
       on_device_model_service_controller_;
diff --git a/components/optimization_guide/core/model_execution/model_execution_manager_unittest.cc b/components/optimization_guide/core/model_execution/model_execution_manager_unittest.cc
index 358fba8..e3ebb77e6 100644
--- a/components/optimization_guide/core/model_execution/model_execution_manager_unittest.cc
+++ b/components/optimization_guide/core/model_execution/model_execution_manager_unittest.cc
@@ -7,12 +7,16 @@
 #include <memory>
 
 #include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "base/test/test.pb.h"
+#include "components/optimization_guide/core/model_execution/on_device_model_access_controller.h"
 #include "components/optimization_guide/core/model_execution/on_device_model_service_controller.h"
 #include "components/optimization_guide/core/optimization_guide_constants.h"
 #include "components/optimization_guide/core/optimization_guide_logger.h"
 #include "components/optimization_guide/core/optimization_guide_util.h"
+#include "components/optimization_guide/core/test_model_info_builder.h"
+#include "components/optimization_guide/core/test_optimization_guide_model_provider.h"
 #include "components/signin/public/identity_manager/identity_test_environment.h"
 #include "components/variations/scoped_variations_ids_provider.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
@@ -22,6 +26,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace optimization_guide {
+
 namespace {
 
 using ::base::test::TestMessage;
@@ -39,19 +44,55 @@
   return execute_response;
 }
 
+class FakeServiceController : public OnDeviceModelServiceController {
+ public:
+  FakeServiceController() : OnDeviceModelServiceController(nullptr, nullptr) {}
+
+  void LaunchService() override {}
+
+  void MaybeUpdateSafetyModel(
+      base::optional_ref<const ModelInfo> model_info) override {
+    received_safety_info_ = true;
+  }
+
+  bool received_safety_info() const { return received_safety_info_; }
+
+ private:
+  ~FakeServiceController() override = default;
+
+  bool received_safety_info_ = false;
+};
+
+class FakeModelProvider : public TestOptimizationGuideModelProvider {
+ public:
+  void AddObserverForOptimizationTargetModel(
+      proto::OptimizationTarget optimization_target,
+      const absl::optional<optimization_guide::proto::Any>& model_metadata,
+      OptimizationTargetModelObserver* observer) override {
+    CHECK_EQ(optimization_target, proto::OPTIMIZATION_TARGET_TEXT_SAFETY);
+    was_registered_ = true;
+  }
+  bool was_registered() const { return was_registered_; }
+
+ private:
+  bool was_registered_ = false;
+};
+
 class ModelExecutionManagerTest : public testing::Test {
  public:
-  ModelExecutionManagerTest() = default;
+  ModelExecutionManagerTest() {
+    scoped_feature_list_.InitAndDisableFeature(features::kTextSafetyClassifier);
+  }
   ~ModelExecutionManagerTest() override = default;
 
   void SetUp() override {
     url_loader_factory_ =
         base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
             &test_url_loader_factory_);
+    service_controller_ = base::MakeRefCounted<FakeServiceController>();
     model_execution_manager_ = std::make_unique<ModelExecutionManager>(
         url_loader_factory_, identity_test_env_.identity_manager(),
-        /*on_device_model_service_controller_=*/nullptr,
-        &optimization_guide_logger_);
+        service_controller_, &model_provider_, &optimization_guide_logger_);
   }
 
   bool SimulateResponse(const std::string& content,
@@ -77,6 +118,12 @@
     return model_execution_manager_.get();
   }
 
+  FakeModelProvider* model_provider() { return &model_provider_; }
+
+  FakeServiceController* service_controller() {
+    return service_controller_.get();
+  }
+
   void CheckPendingRequestMessage(const std::string& message) {
     EXPECT_EQ(test_url_loader_factory_.NumPending(), 1);
     auto* pending_request = test_url_loader_factory_.GetPendingRequest(0);
@@ -89,11 +136,14 @@
 
  private:
   base::test::TaskEnvironment task_environment_;
+  base::test::ScopedFeatureList scoped_feature_list_;
   signin::IdentityTestEnvironment identity_test_env_;
   variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{
       variations::VariationsIdsProvider::Mode::kUseSignedInState};
   scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
   network::TestURLLoaderFactory test_url_loader_factory_;
+  scoped_refptr<FakeServiceController> service_controller_;
+  FakeModelProvider model_provider_;
   OptimizationGuideLogger optimization_guide_logger_;
   std::unique_ptr<ModelExecutionManager> model_execution_manager_;
 };
@@ -438,6 +488,45 @@
   run_loop.Run();
 }
 
+TEST_F(ModelExecutionManagerTest, DoesNotRegisterTextSafetyIfNotEnabled) {
+  EXPECT_FALSE(model_provider()->was_registered());
+}
+
+class ModelExecutionManagerSafetyEnabledTest
+    : public ModelExecutionManagerTest {
+ public:
+  ModelExecutionManagerSafetyEnabledTest() {
+    scoped_feature_list_.InitAndEnableFeature(features::kTextSafetyClassifier);
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+TEST_F(ModelExecutionManagerSafetyEnabledTest,
+       RegistersTextSafetyModelIfEnabled) {
+  EXPECT_TRUE(model_provider()->was_registered());
+}
+
+TEST_F(ModelExecutionManagerSafetyEnabledTest,
+       DoesNotNotifyServiceControllerWrongTarget) {
+  std::unique_ptr<ModelInfo> model_info =
+      TestModelInfoBuilder().SetVersion(123).Build();
+  model_execution_manager()->OnModelUpdated(
+      proto::OPTIMIZATION_TARGET_PAGE_ENTITIES, *model_info);
+
+  EXPECT_FALSE(service_controller()->received_safety_info());
+}
+
+TEST_F(ModelExecutionManagerSafetyEnabledTest, NotifiesServiceController) {
+  std::unique_ptr<ModelInfo> model_info =
+      TestModelInfoBuilder().SetVersion(123).Build();
+  model_execution_manager()->OnModelUpdated(
+      proto::OPTIMIZATION_TARGET_TEXT_SAFETY, *model_info);
+
+  EXPECT_TRUE(service_controller()->received_safety_info());
+}
+
 }  // namespace
 
 }  // namespace optimization_guide
diff --git a/components/optimization_guide/core/model_execution/model_execution_prefs.cc b/components/optimization_guide/core/model_execution/model_execution_prefs.cc
index 9ae30e1..9170025d 100644
--- a/components/optimization_guide/core/model_execution/model_execution_prefs.cc
+++ b/components/optimization_guide/core/model_execution/model_execution_prefs.cc
@@ -43,6 +43,7 @@
       return kTabOrganizationEnterprisePolicyAllowed;
     case proto::ModelExecutionFeature::MODEL_EXECUTION_FEATURE_WALLPAPER_SEARCH:
       return kWallpaperSearchEnterprisePolicyAllowed;
+    case proto::ModelExecutionFeature::MODEL_EXECUTION_FEATURE_TEST:
     case proto::ModelExecutionFeature::MODEL_EXECUTION_FEATURE_UNSPECIFIED:
       NOTREACHED();
       return nullptr;
diff --git a/components/optimization_guide/core/model_execution/model_execution_util.cc b/components/optimization_guide/core/model_execution/model_execution_util.cc
index 552ec41..be5a80e 100644
--- a/components/optimization_guide/core/model_execution/model_execution_util.cc
+++ b/components/optimization_guide/core/model_execution/model_execution_util.cc
@@ -27,6 +27,9 @@
       SetExecutionRequestTemplate<ComposeFeatureTypeMap>(log_ai_request,
                                                          request_metadata);
       return;
+    case proto::ModelExecutionFeature::MODEL_EXECUTION_FEATURE_TEST:
+      // Do not log request for test.
+      return;
     case proto::ModelExecutionFeature::MODEL_EXECUTION_FEATURE_UNSPECIFIED:
       // Don't log any request data when the feature is not specified.
       NOTREACHED();
@@ -52,6 +55,9 @@
       SetExecutionResponseTemplate<ComposeFeatureTypeMap>(log_ai_request,
                                                           response_metadata);
       return;
+    case proto::ModelExecutionFeature::MODEL_EXECUTION_FEATURE_TEST:
+      // Do not log response for test.
+      return;
     case proto::ModelExecutionFeature::MODEL_EXECUTION_FEATURE_UNSPECIFIED:
       // Don't log any response data when the feature is not specified.
       NOTREACHED();
diff --git a/components/optimization_guide/core/model_execution/on_device_model_service_controller.cc b/components/optimization_guide/core/model_execution/on_device_model_service_controller.cc
index c1337fb..44173e1 100644
--- a/components/optimization_guide/core/model_execution/on_device_model_service_controller.cc
+++ b/components/optimization_guide/core/model_execution/on_device_model_service_controller.cc
@@ -60,6 +60,11 @@
   }
 }
 
+bool HasRequiredSafetyFiles(const ModelInfo& model_info) {
+  return model_info.GetAdditionalFileWithBaseName(kTsDataFile) &&
+         model_info.GetAdditionalFileWithBaseName(kTsSpModelFile);
+}
+
 }  // namespace
 
 OnDeviceModelServiceController::OnDeviceModelServiceController(
@@ -89,8 +94,12 @@
   model_paths.sp_model = model_path.Append(kSpModelFile);
   model_paths.model = model_path.Append(kModelFile);
   model_paths.weights = model_path.Append(kWeightsFile);
-  model_paths.ts_data = model_path.Append(kTsDataFile);
-  model_paths.ts_sp_model = model_path.Append(kTsSpModelFile);
+  if (safety_model_info_) {
+    model_paths.ts_data =
+        *(safety_model_info_->GetAdditionalFileWithBaseName(kTsDataFile));
+    model_paths.ts_sp_model =
+        *(safety_model_info_->GetAdditionalFileWithBaseName(kTsSpModelFile));
+  }
   model_paths_ = std::move(model_paths);
   config_interpreter_ = std::move(config_interpreter);
   config_interpreter_->UpdateConfigWithFileDir(model_path);
@@ -121,7 +130,9 @@
     proto::ModelExecutionFeature feature,
     ExecuteRemoteFn execute_remote_fn,
     OptimizationGuideLogger* optimization_guide_logger) {
-  on_device_component_state_manager_->OnDeviceEligibleFeatureUsed();
+  if (on_device_component_state_manager_) {
+    on_device_component_state_manager_->OnDeviceEligibleFeatureUsed();
+  }
   ScopedEligibilityReasonLogger logger(feature);
   if (!base::FeatureList::IsEnabled(
           features::kOptimizationGuideOnDeviceModel)) {
@@ -132,6 +143,11 @@
     logger.set_reason(OnDeviceModelEligibilityReason::kModelNotAvailable);
     return nullptr;
   }
+  if (features::GetOnDeviceModelMustUseSafetyModel() &&
+      !model_paths_->HasSafetyFiles()) {
+    logger.set_reason(OnDeviceModelEligibilityReason::kSafetyModelNotAvailable);
+    return nullptr;
+  }
   if (!config_interpreter_->HasConfigForFeature(feature)) {
     logger.set_reason(
         OnDeviceModelEligibilityReason::kConfigNotAvailableForFeature);
@@ -207,6 +223,28 @@
                      weak_ptr_factory_.GetWeakPtr()));
 }
 
+void OnDeviceModelServiceController::MaybeUpdateSafetyModel(
+    base::optional_ref<const ModelInfo> model_info) {
+  if (model_info.has_value() && HasRequiredSafetyFiles(*model_info)) {
+    safety_model_info_ = *model_info;
+
+    // Update the paths if this exists to be used in subsequent sessions.
+    if (model_paths_) {
+      model_paths_->ts_data =
+          *(safety_model_info_->GetAdditionalFileWithBaseName(kTsDataFile));
+      model_paths_->ts_sp_model =
+          *(safety_model_info_->GetAdditionalFileWithBaseName(kTsSpModelFile));
+    }
+  } else if (model_paths_) {
+    safety_model_info_ = std::nullopt;
+    // Clear out T&S model paths if we shouldn't use the current safety model
+    // anymore. The current active session will still use the safety model
+    // though, if already using it.
+    model_paths_->ts_data = base::FilePath();
+    model_paths_->ts_sp_model = base::FilePath();
+  }
+}
+
 void OnDeviceModelServiceController::StateChanged(
     const OnDeviceModelComponentState* state) {
   if (state && !model_paths_) {
diff --git a/components/optimization_guide/core/model_execution/on_device_model_service_controller.h b/components/optimization_guide/core/model_execution/on_device_model_service_controller.h
index 690f6ff4..6f80b3f 100644
--- a/components/optimization_guide/core/model_execution/on_device_model_service_controller.h
+++ b/components/optimization_guide/core/model_execution/on_device_model_service_controller.h
@@ -14,9 +14,11 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
+#include "base/types/optional_ref.h"
 #include "base/types/pass_key.h"
 #include "components/optimization_guide/core/model_execution/on_device_model_component.h"
 #include "components/optimization_guide/core/model_execution/session_impl.h"
+#include "components/optimization_guide/core/model_info.h"
 #include "components/optimization_guide/core/optimization_guide_model_executor.h"
 #include "components/optimization_guide/proto/model_execution.pb.h"
 #include "mojo/public/cpp/bindings/remote.h"
@@ -50,7 +52,7 @@
     : public base::RefCounted<OnDeviceModelServiceController>,
       public OnDeviceModelComponentStateManager::Observer {
  public:
-  explicit OnDeviceModelServiceController(
+  OnDeviceModelServiceController(
       std::unique_ptr<OnDeviceModelAccessController> access_controller,
       base::WeakPtr<OnDeviceModelComponentStateManager>
           on_device_component_state_manager);
@@ -95,17 +97,23 @@
     return model_remote_.is_bound() || service_remote_.is_bound();
   }
 
+  // Updates safety model if the model path provided by `model_info` differs
+  // from what is already loaded. Virtual for testing.
+  virtual void MaybeUpdateSafetyModel(
+      base::optional_ref<const ModelInfo> model_info);
+
   // OnDeviceModelComponentStateManager::Observer.
   void StateChanged(const OnDeviceModelComponentState* state) override;
 
+ protected:
+  ~OnDeviceModelServiceController() override;
+
  private:
   friend class base::RefCounted<OnDeviceModelServiceController>;
   friend class ChromeOnDeviceModelServiceController;
   friend class OnDeviceModelServiceControllerTest;
   friend class FakeOnDeviceModelServiceController;
 
-  ~OnDeviceModelServiceController() override;
-
   // Makes sure the service is running and starts a mojo session.
   void StartMojoSession(
       mojo::PendingReceiver<on_device_model::mojom::Session> session);
@@ -131,6 +139,7 @@
   base::WeakPtr<OnDeviceModelComponentStateManager>
       on_device_component_state_manager_;
   std::optional<on_device_model::ModelAssetPaths> model_paths_;
+  std::optional<ModelInfo> safety_model_info_;
   std::unique_ptr<OnDeviceModelExecutionConfigInterpreter> config_interpreter_;
   mojo::Remote<on_device_model::mojom::OnDeviceModelService> service_remote_;
   mojo::Remote<on_device_model::mojom::OnDeviceModel> model_remote_;
diff --git a/components/optimization_guide/core/model_execution/on_device_model_service_controller_unittest.cc b/components/optimization_guide/core/model_execution/on_device_model_service_controller_unittest.cc
index 51cbdf5..927f98a 100644
--- a/components/optimization_guide/core/model_execution/on_device_model_service_controller_unittest.cc
+++ b/components/optimization_guide/core/model_execution/on_device_model_service_controller_unittest.cc
@@ -6,6 +6,7 @@
 #include <memory>
 #include <optional>
 
+#include "base/files/scoped_temp_dir.h"
 #include "base/functional/callback_helpers.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/test/bind.h"
@@ -15,10 +16,12 @@
 #include "components/optimization_guide/core/model_execution/on_device_model_access_controller.h"
 #include "components/optimization_guide/core/model_execution/on_device_model_execution_config_interpreter.h"
 #include "components/optimization_guide/core/model_execution/test_on_device_model_component.h"
+#include "components/optimization_guide/core/optimization_guide_constants.h"
 #include "components/optimization_guide/core/optimization_guide_features.h"
 #include "components/optimization_guide/core/optimization_guide_logger.h"
 #include "components/optimization_guide/core/optimization_guide_prefs.h"
 #include "components/optimization_guide/core/optimization_guide_util.h"
+#include "components/optimization_guide/core/test_model_info_builder.h"
 #include "components/optimization_guide/proto/features/compose.pb.h"
 #include "components/prefs/testing_pref_service.h"
 #include "mojo/public/cpp/bindings/unique_receiver_set.h"
@@ -185,7 +188,7 @@
 class FakeOnDeviceModelServiceController
     : public OnDeviceModelServiceController {
  public:
-  explicit FakeOnDeviceModelServiceController(
+  FakeOnDeviceModelServiceController(
       std::unique_ptr<OnDeviceModelAccessController> access_controller,
       base::WeakPtr<OnDeviceModelComponentStateManager>
           on_device_component_state_manager)
@@ -225,13 +228,15 @@
 class OnDeviceModelServiceControllerTest : public testing::Test {
  public:
   void SetUp() override {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     g_execute_delay = base::TimeDelta();
     g_on_complete_response_type = on_device_model::mojom::ResponseStatus::kOk;
     feature_list_.InitAndEnableFeatureWithParameters(
         features::kOptimizationGuideOnDeviceModel,
         {{"on_device_model_min_tokens_for_context", "10"},
          {"on_device_model_max_tokens_for_context", "22"},
-         {"on_device_model_context_token_chunk_size", "4"}});
+         {"on_device_model_context_token_chunk_size", "4"},
+         {"on_device_must_use_safety_model", "false"}});
     prefs::RegisterLocalStatePrefs(pref_service_.registry());
     RecreateServiceController();
   }
@@ -325,6 +330,8 @@
                             base::Unretained(this)));
   }
 
+  base::FilePath temp_dir() const { return temp_dir_.GetPath(); }
+
  protected:
   void OnResponse(OptimizationGuideModelStreamingExecutionResult result,
                   std::unique_ptr<ModelQualityLogEntry> log_entry) {
@@ -344,6 +351,7 @@
 
   base::test::TaskEnvironment task_environment_{
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+  base::ScopedTempDir temp_dir_;
   TestingPrefServiceSimple pref_service_;
   TestOnDeviceModelComponentStateManager on_device_component_state_manager_{
       &pref_service_};
@@ -483,6 +491,79 @@
       OnDeviceModelEligibilityReason::kConfigNotAvailableForFeature, 1);
 }
 
+TEST_F(OnDeviceModelServiceControllerTest, SessionRequiresSafetyModel) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeatureWithParameters(
+      features::kOptimizationGuideOnDeviceModel,
+      {{"on_device_must_use_safety_model", "true"}});
+
+  // No safety model received yet.
+  {
+    base::HistogramTester histogram_tester;
+
+    EXPECT_FALSE(
+        test_controller_->CreateSession(kFeature, base::DoNothing(), &logger_));
+
+    histogram_tester.ExpectUniqueSample(
+        "OptimizationGuide.ModelExecution.OnDeviceModelEligibilityReason."
+        "Compose",
+        OnDeviceModelEligibilityReason::kSafetyModelNotAvailable, 1);
+  }
+
+  // Safety model info is valid, session created successfully.
+  {
+    base::HistogramTester histogram_tester;
+
+    std::unique_ptr<optimization_guide::ModelInfo> model_info =
+        TestModelInfoBuilder()
+            .SetAdditionalFiles(
+                {temp_dir().Append(kTsDataFile),
+                 temp_dir().Append(base::FilePath(kTsSpModelFile))})
+            .Build();
+    test_controller_->MaybeUpdateSafetyModel(*model_info);
+    EXPECT_TRUE(
+        test_controller_->CreateSession(kFeature, base::DoNothing(), &logger_));
+
+    histogram_tester.ExpectUniqueSample(
+        "OptimizationGuide.ModelExecution.OnDeviceModelEligibilityReason."
+        "Compose",
+        OnDeviceModelEligibilityReason::kSuccess, 1);
+  }
+
+  // Safety model reset to not available, session no longer created
+  // successfully.
+  {
+    base::HistogramTester histogram_tester;
+
+    test_controller_->MaybeUpdateSafetyModel(std::nullopt);
+    EXPECT_FALSE(
+        test_controller_->CreateSession(kFeature, base::DoNothing(), &logger_));
+
+    histogram_tester.ExpectUniqueSample(
+        "OptimizationGuide.ModelExecution.OnDeviceModelEligibilityReason."
+        "Compose",
+        OnDeviceModelEligibilityReason::kSafetyModelNotAvailable, 1);
+  }
+
+  // Safety model reset to invalid, session no longer created successfully.
+  {
+    base::HistogramTester histogram_tester;
+
+    std::unique_ptr<ModelInfo> model_info =
+        TestModelInfoBuilder()
+            .SetModelFilePath(temp_dir().Append(FILE_PATH_LITERAL("garbage")))
+            .Build();
+    test_controller_->MaybeUpdateSafetyModel(*model_info);
+    EXPECT_FALSE(
+        test_controller_->CreateSession(kFeature, base::DoNothing(), &logger_));
+
+    histogram_tester.ExpectUniqueSample(
+        "OptimizationGuide.ModelExecution.OnDeviceModelEligibilityReason."
+        "Compose",
+        OnDeviceModelEligibilityReason::kSafetyModelNotAvailable, 1);
+  }
+}
+
 TEST_F(OnDeviceModelServiceControllerTest, ModelExecutionNoMinContext) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeatureWithParameters(
diff --git a/components/optimization_guide/core/model_quality/model_quality_logs_uploader_service.cc b/components/optimization_guide/core/model_quality/model_quality_logs_uploader_service.cc
index 19d8e21..9423790 100644
--- a/components/optimization_guide/core/model_quality/model_quality_logs_uploader_service.cc
+++ b/components/optimization_guide/core/model_quality/model_quality_logs_uploader_service.cc
@@ -10,6 +10,7 @@
 #include "components/optimization_guide/core/access_token_helper.h"
 #include "components/optimization_guide/core/model_quality/model_quality_log_entry.h"
 #include "components/optimization_guide/core/optimization_guide_constants.h"
+#include "components/optimization_guide/core/optimization_guide_enums.h"
 #include "components/optimization_guide/core/optimization_guide_features.h"
 #include "components/optimization_guide/core/optimization_guide_logger.h"
 #include "components/optimization_guide/core/optimization_guide_switches.h"
@@ -28,6 +29,15 @@
 
 namespace {
 
+void RecordUploadStatusHistogram(proto::ModelExecutionFeature feature,
+                                 ModelQualityLogsUploadStatus status) {
+  base::UmaHistogramEnumeration(
+      base::StrCat(
+          {"OptimizationGuide.ModelQualityLogsUploadService.UploadStatus.",
+           GetStringNameForModelExecutionFeature(feature)}),
+      status);
+}
+
 // Returns the URL endpoint for the model quality service along with the needed
 // API key.
 GURL GetModelQualityLogsUploaderServiceURL() {
@@ -62,6 +72,7 @@
 // URL load completion callback.
 void OnURLLoadComplete(
     std::unique_ptr<network::SimpleURLLoader> active_url_loader,
+    proto::ModelExecutionFeature feature,
     std::unique_ptr<std::string> response_body) {
   CHECK(active_url_loader) << "loader shouldn't be null\n";
   auto net_error = active_url_loader->NetError();
@@ -81,6 +92,14 @@
   base::UmaHistogramSparse(
       "OptimizationGuide.ModelQualityLogsUploaderService.NetErrorCode",
       -net_error);
+
+  if (net_error != net::OK || response_code != net::HTTP_OK) {
+    RecordUploadStatusHistogram(feature,
+                                ModelQualityLogsUploadStatus::kNetError);
+    return;
+  }
+  RecordUploadStatusHistogram(feature,
+                              ModelQualityLogsUploadStatus::kUploadSuccessful);
 }
 
 }  // namespace
@@ -120,6 +139,8 @@
   // Don't do anything if logging is disabled for the feature. Nothing to
   // upload.
   if (!features::IsModelQualityLoggingEnabledForFeature(feature)) {
+    RecordUploadStatusHistogram(
+        feature, ModelQualityLogsUploadStatus::kLoggingNotEnabled);
     return;
   }
 
@@ -158,7 +179,8 @@
   auto* active_url_loader_ptr = active_url_loader.get();
   active_url_loader_ptr->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
       url_loader_factory_.get(),
-      base::BindOnce(&OnURLLoadComplete, std::move(active_url_loader)));
+      base::BindOnce(&OnURLLoadComplete, std::move(active_url_loader),
+                     feature));
 }
 
 }  // namespace optimization_guide
diff --git a/components/optimization_guide/core/model_quality/model_quality_logs_uploader_service_unittest.cc b/components/optimization_guide/core/model_quality/model_quality_logs_uploader_service_unittest.cc
index 5acd09bf..47db38d 100644
--- a/components/optimization_guide/core/model_quality/model_quality_logs_uploader_service_unittest.cc
+++ b/components/optimization_guide/core/model_quality/model_quality_logs_uploader_service_unittest.cc
@@ -171,6 +171,9 @@
       -net::OK, 1);
   histogram_tester_.ExpectTotalCount(
       "OptimizationGuide.ModelQualityLogsUploaderService.Status", 1);
+  histogram_tester_.ExpectUniqueSample(
+      "OptimizationGuide.ModelQualityLogsUploadService.UploadStatus.Compose",
+      ModelQualityLogsUploadStatus::kUploadSuccessful, 1);
 }
 
 TEST_F(ModelQualityLogsUploaderServiceTest, TestMultipleUploads) {
@@ -195,6 +198,9 @@
       -net::OK, 2);
   histogram_tester_.ExpectTotalCount(
       "OptimizationGuide.ModelQualityLogsUploaderService.Status", 2);
+  histogram_tester_.ExpectUniqueSample(
+      "OptimizationGuide.ModelQualityLogsUploadService.UploadStatus.Compose",
+      ModelQualityLogsUploadStatus::kUploadSuccessful, 2);
 }
 
 TEST_F(ModelQualityLogsUploaderServiceTest, TestUploadWhenLoggingDisabled) {
@@ -208,6 +214,9 @@
 
   // When logging is disabled there should be no pending requests.
   VerifyNumberOfPendingRequests(0);
+  histogram_tester_.ExpectUniqueSample(
+      "OptimizationGuide.ModelQualityLogsUploadService.UploadStatus.Compose",
+      ModelQualityLogsUploadStatus::kLoggingNotEnabled, 1);
 }
 
 TEST_F(ModelQualityLogsUploaderServiceTest, TestUploadWhenRequestIsEmpty) {
@@ -231,6 +240,10 @@
       net::HTTP_NOT_FOUND, 1);
   histogram_tester_.ExpectTotalCount(
       "OptimizationGuide.ModelQualityLogsUploaderService.NetErrorCode", 1);
+
+  histogram_tester_.ExpectUniqueSample(
+      "OptimizationGuide.ModelQualityLogsUploadService.UploadStatus.Compose",
+      ModelQualityLogsUploadStatus::kNetError, 1);
 }
 
 TEST_F(ModelQualityLogsUploaderServiceTest, TestBadResponse) {
diff --git a/components/optimization_guide/core/optimization_guide_enums.h b/components/optimization_guide/core/optimization_guide_enums.h
index 2ad52cc..282974a7 100644
--- a/components/optimization_guide/core/optimization_guide_enums.h
+++ b/components/optimization_guide/core/optimization_guide_enums.h
@@ -258,12 +258,31 @@
   kTooManyRecentCrashes = 6,
   // The on-device model took too long too many times for this version.
   kTooManyRecentTimeouts = 7,
+  // The on-device safety model was required but not available.
+  kSafetyModelNotAvailable = 8,
 
   // This must be kept in sync with
   // OptimizationGuideOnDeviceModelEligibilityReason in optimization/enums.xml.
 
   // Insert new values before this line.
-  kMaxValue = kTooManyRecentTimeouts,
+  kMaxValue = kSafetyModelNotAvailable,
+};
+
+// Status of a model quality logs upload request.
+enum class ModelQualityLogsUploadStatus {
+  kUnknown = 0,
+  // Logs upload was successful.
+  kUploadSuccessful = 1,
+  // Upload is disabled due to logging feature not enabled.
+  kLoggingNotEnabled = 2,
+  // Upload was not successful because of network error.
+  kNetError = 3,
+
+  // Insert new values before this line.
+  // This enum must remain synchronized with the enum
+  // |OptimizationGuideModelQualityLogsUploadStatus| in
+  // tools/metrics/histograms/enums.xml.
+  kMaxValue = kNetError,
 };
 
 // Performance class of this device.
diff --git a/components/optimization_guide/core/optimization_guide_features.cc b/components/optimization_guide/core/optimization_guide_features.cc
index 4ea2f988..4373a00 100644
--- a/components/optimization_guide/core/optimization_guide_features.cc
+++ b/components/optimization_guide/core/optimization_guide_features.cc
@@ -314,6 +314,11 @@
              "LogOnDeviceMetricsOnStartup",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Whether to download the text safety classifier model.
+BASE_FEATURE(kTextSafetyClassifier,
+             "TextSafetyClassifier",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 size_t MaxRelatedSearchesCacheSize() {
   return GetFieldTrialParamByFeatureAsInt(
       kExtractRelatedSearchesFromPrefetchedZPSResponse,
@@ -435,6 +440,11 @@
     return false;
   }
 
+  if (feature_name ==
+      proto::ModelExecutionFeature::MODEL_EXECUTION_FEATURE_TEST) {
+    return false;
+  }
+
   std::string param_name =
       base::ToLowerASCII(proto::ModelExecutionFeature_Name(feature_name));
   bool default_value = true;
@@ -1033,5 +1043,17 @@
   return kOnDeviceModelShouldRetractUnsafeContent.Get();
 }
 
+bool GetOnDeviceModelMustUseSafetyModel() {
+  static const base::FeatureParam<bool>
+      kOnDeviceModelShouldRetractUnsafeContent{
+          &kOptimizationGuideOnDeviceModel, "on_device_must_use_safety_model",
+          false};
+  return kOnDeviceModelShouldRetractUnsafeContent.Get();
+}
+
+bool ShouldDownloadTextSafetyClassifierModel() {
+  return base::FeatureList::IsEnabled(kTextSafetyClassifier);
+}
+
 }  // namespace features
 }  // namespace optimization_guide
diff --git a/components/optimization_guide/core/optimization_guide_features.h b/components/optimization_guide/core/optimization_guide_features.h
index 5c2579ec..527869d 100644
--- a/components/optimization_guide/core/optimization_guide_features.h
+++ b/components/optimization_guide/core/optimization_guide_features.h
@@ -95,6 +95,8 @@
 BASE_DECLARE_FEATURE(kModelQualityLogging);
 COMPONENT_EXPORT(OPTIMIZATION_GUIDE_FEATURES)
 BASE_DECLARE_FEATURE(kLogOnDeviceMetricsOnStartup);
+COMPONENT_EXPORT(OPTIMIZATION_GUIDE_FEATURES)
+BASE_DECLARE_FEATURE(kTextSafetyClassifier);
 
 // Enables use of task runner with trait CONTINUE_ON_SHUTDOWN for page content
 // annotations on-device models.
@@ -560,6 +562,14 @@
 COMPONENT_EXPORT(OPTIMIZATION_GUIDE_FEATURES)
 bool GetOnDeviceModelRetractUnsafeContent();
 
+// Returns true if the safety model must be used.
+COMPONENT_EXPORT(OPTIMIZATION_GUIDE_FEATURES)
+bool GetOnDeviceModelMustUseSafetyModel();
+
+// Whether we should initiate download of the text safety classifier model.
+COMPONENT_EXPORT(OPTIMIZATION_GUIDE_FEATURES)
+bool ShouldDownloadTextSafetyClassifierModel();
+
 }  // namespace features
 }  // namespace optimization_guide
 
diff --git a/components/optimization_guide/core/optimization_guide_prefs.cc b/components/optimization_guide/core/optimization_guide_prefs.cc
index 93dcd09..0a3f6d21 100644
--- a/components/optimization_guide/core/optimization_guide_prefs.cc
+++ b/components/optimization_guide/core/optimization_guide_prefs.cc
@@ -73,6 +73,7 @@
       return "optimization_guide.tab_organization_setting_state";
     case proto::ModelExecutionFeature::MODEL_EXECUTION_FEATURE_WALLPAPER_SEARCH:
       return "optimization_guide.wallpaper_search_setting_state";
+    case proto::ModelExecutionFeature::MODEL_EXECUTION_FEATURE_TEST:
     case proto::ModelExecutionFeature::MODEL_EXECUTION_FEATURE_UNSPECIFIED:
       NOTREACHED();
       return "Invalid";
@@ -89,6 +90,7 @@
     proto::ModelExecutionFeature feature =
         static_cast<proto::ModelExecutionFeature>(i);
     switch (feature) {
+      case proto::ModelExecutionFeature::MODEL_EXECUTION_FEATURE_TEST:
       case proto::ModelExecutionFeature::MODEL_EXECUTION_FEATURE_UNSPECIFIED:
         continue;
       default:
diff --git a/components/optimization_guide/core/optimization_guide_util.cc b/components/optimization_guide/core/optimization_guide_util.cc
index 64d64e9e..b56df1c 100644
--- a/components/optimization_guide/core/optimization_guide_util.cc
+++ b/components/optimization_guide/core/optimization_guide_util.cc
@@ -85,6 +85,8 @@
       return "TabOrganization";
     case proto::ModelExecutionFeature::MODEL_EXECUTION_FEATURE_COMPOSE:
       return "Compose";
+    case proto::ModelExecutionFeature::MODEL_EXECUTION_FEATURE_TEST:
+      return "Test";
     case proto::ModelExecutionFeature::MODEL_EXECUTION_FEATURE_UNSPECIFIED:
       return "Unknown";
       // Must be in sync with the ModelExecutionFeature variant in
diff --git a/components/optimization_guide/proto/model_execution.proto b/components/optimization_guide/proto/model_execution.proto
index 19ec557e..2962e64 100644
--- a/components/optimization_guide/proto/model_execution.proto
+++ b/components/optimization_guide/proto/model_execution.proto
@@ -54,6 +54,10 @@
   MODEL_EXECUTION_FEATURE_COMPOSE = 1;
   MODEL_EXECUTION_FEATURE_TAB_ORGANIZATION = 2;
   MODEL_EXECUTION_FEATURE_WALLPAPER_SEARCH = 3;
+  // This test feature cannot be used for launch but can be used for
+  // prototyping. Please reach out to optimization_guide OWNERS when looking to
+  // use this enum or want to go beyond prototyping.
+  MODEL_EXECUTION_FEATURE_TEST = 4;
 }
 
 message OnDeviceModelExecutionConfig {
diff --git a/components/page_image_service/image_service_consent_helper.cc b/components/page_image_service/image_service_consent_helper.cc
index 1522abaa..1ddd6e2 100644
--- a/components/page_image_service/image_service_consent_helper.cc
+++ b/components/page_image_service/image_service_consent_helper.cc
@@ -103,14 +103,19 @@
     return;
   }
 
-  for (auto& request_callback_with_client_id : enqueued_request_callbacks_) {
+  request_processing_timer_.Stop();
+
+  // The request callbacks can modify the vector while running. Swap the vector
+  // onto the stack to prevent crashing. https://crbug.com/1472360.
+  std::vector<std::pair<base::OnceCallback<void(PageImageServiceConsentStatus)>,
+                        mojom::ClientId>>
+      callbacks;
+  std::swap(callbacks, enqueued_request_callbacks_);
+  for (auto& request_callback_with_client_id : callbacks) {
     std::move(request_callback_with_client_id.first)
         .Run(*consent_status ? PageImageServiceConsentStatus::kSuccess
                              : PageImageServiceConsentStatus::kFailure);
   }
-
-  enqueued_request_callbacks_.clear();
-  request_processing_timer_.Stop();
 }
 
 void ImageServiceConsentHelper::OnSyncShutdown(
@@ -142,7 +147,13 @@
 }
 
 void ImageServiceConsentHelper::OnTimeoutExpired() {
-  for (auto& request_callback_with_client_id : enqueued_request_callbacks_) {
+  // The request callbacks can modify the vector while running. Swap the vector
+  // onto the stack to prevent crashing. https://crbug.com/1472360.
+  std::vector<std::pair<base::OnceCallback<void(PageImageServiceConsentStatus)>,
+                        mojom::ClientId>>
+      callbacks;
+  std::swap(callbacks, enqueued_request_callbacks_);
+  for (auto& request_callback_with_client_id : callbacks) {
     // Report consent status on timeout for each request to compare against the
     // number of all requests.
     PageImageServiceConsentStatus consent_status =
@@ -159,7 +170,6 @@
     }
     std::move(request_callback_with_client_id.first).Run(consent_status);
   }
-  enqueued_request_callbacks_.clear();
 }
 
 }  // namespace page_image_service
diff --git a/components/page_image_service/image_service_consent_helper_unittest.cc b/components/page_image_service/image_service_consent_helper_unittest.cc
index 7cd2842..ef2c743 100644
--- a/components/page_image_service/image_service_consent_helper_unittest.cc
+++ b/components/page_image_service/image_service_consent_helper_unittest.cc
@@ -179,6 +179,47 @@
   EXPECT_THAT(results, ElementsAre(PageImageServiceConsentStatus::kFailure));
 }
 
+// In production, sometimes the callback to a request enqueues a new request.
+// This tests this case and fixes the crash in https://crbug.com/1472360.
+TEST_F(ImageServiceConsentHelperTest, CallbacksMakingNewRequests) {
+  SetDownloadStatusAndFireNotification(
+      syncer::SyncService::ModelTypeDownloadStatus::kWaitingForUpdates);
+
+  std::vector<PageImageServiceConsentStatus> results;
+
+  // These two blocks are identical. The crash is reliably triggered when
+  // adding two of these. Probably having two pushes the vector to reallocate
+  // while iterating.
+  consent_helper()->EnqueueRequest(
+      base::BindLambdaForTesting([&](PageImageServiceConsentStatus result) {
+        results.push_back(result);
+        consent_helper()->EnqueueRequest(
+            base::BindLambdaForTesting(
+                [&](PageImageServiceConsentStatus result2) {
+                  results.push_back(result2);
+                }),
+            mojom::ClientId::Bookmarks);
+      }),
+      mojom::ClientId::Bookmarks);
+  consent_helper()->EnqueueRequest(
+      base::BindLambdaForTesting([&](PageImageServiceConsentStatus result) {
+        results.push_back(result);
+        consent_helper()->EnqueueRequest(
+            base::BindLambdaForTesting(
+                [&](PageImageServiceConsentStatus result2) {
+                  results.push_back(result2);
+                }),
+            mojom::ClientId::Bookmarks);
+      }),
+      mojom::ClientId::Bookmarks);
+
+  // New requests added during iteration live as long as the NEXT timeout.
+  FastForwardBy(base::Seconds(12));
+  EXPECT_EQ(results.size(), 2U);
+  FastForwardBy(base::Seconds(12));
+  EXPECT_EQ(results.size(), 4U);
+}
+
 class ImageServiceConsentHelperDownloadStatusKillSwitchTest
     : public ImageServiceConsentHelperTest {
  public:
diff --git a/components/password_manager/core/browser/origin_credential_store.cc b/components/password_manager/core/browser/origin_credential_store.cc
index 7195449..0742cfb 100644
--- a/components/password_manager/core/browser/origin_credential_store.cc
+++ b/components/password_manager/core/browser/origin_credential_store.cc
@@ -114,6 +114,16 @@
   return credentials_;
 }
 
+void OriginCredentialStore::SaveUnnotifiedSharedCredentials(
+    std::vector<PasswordForm> credentials) {
+  unnotified_shared_credentials_ = std::move(credentials);
+}
+
+base::span<const PasswordForm>
+OriginCredentialStore::GetUnnotifiedSharedCredentials() const {
+  return unnotified_shared_credentials_;
+}
+
 void OriginCredentialStore::SetBlocklistedStatus(bool is_blocklisted) {
   if (is_blocklisted) {
     blocklisted_status_ = BlocklistedStatus::kIsBlocklisted;
diff --git a/components/password_manager/core/browser/origin_credential_store.h b/components/password_manager/core/browser/origin_credential_store.h
index 18c13fd7..b7d0dbe 100644
--- a/components/password_manager/core/browser/origin_credential_store.h
+++ b/components/password_manager/core/browser/origin_credential_store.h
@@ -101,9 +101,19 @@
   // Saves credentials so that they can be used in the UI.
   void SaveCredentials(std::vector<UiCredential> credentials);
 
-  // Returns references to the held credentials (or an empty set if aren't any).
+  // Returns references to the held credentials (or an empty set if there aren't
+  // any).
   base::span<const UiCredential> GetCredentials() const;
 
+  // Saved credentials that have been received via the password sharing feature
+  // and not yet notified to the user. This is important to mark them notified
+  // upon user interaction with the UI.
+  void SaveUnnotifiedSharedCredentials(std::vector<PasswordForm> credentials);
+
+  // Returns references to the held unnotified shared credentials (or an empty
+  // set if there aren't any).
+  base::span<const PasswordForm> GetUnnotifiedSharedCredentials() const;
+
   // Sets the blocklisted status. The possible transitions are:
   // (*, is_blocklisted = true) -> kIsBlocklisted
   // ((kIsBlocklisted|kWasBlocklisted), is_blocklisted = false)
@@ -124,6 +134,10 @@
   // Contains all previously stored of credentials.
   std::vector<UiCredential> credentials_;
 
+  // Contains all credentials that have been received via the password sharing
+  // feature and not yet notified to the user.
+  std::vector<PasswordForm> unnotified_shared_credentials_;
+
   // The blocklisted status for |origin_|.
   // Used to know whether unblocklisting UI needs to be displayed and what
   // state it should display;
diff --git a/components/password_manager/core/browser/origin_credential_store_unittest.cc b/components/password_manager/core/browser/origin_credential_store_unittest.cc
index 8a51b37..c0320026 100644
--- a/components/password_manager/core/browser/origin_credential_store_unittest.cc
+++ b/components/password_manager/core/browser/origin_credential_store_unittest.cc
@@ -38,6 +38,15 @@
                       base::Time());
 }
 
+password_manager::PasswordForm CreateTestPasswordForm(int index = 0) {
+  password_manager::PasswordForm form;
+  form.url = GURL("https://test" + base::NumberToString(index) + ".com");
+  form.signon_realm = form.url.spec();
+  form.username_value = u"username" + base::NumberToString16(index);
+  form.password_value = u"password" + base::NumberToString16(index);
+  return form;
+}
+
 }  // namespace
 
 class OriginCredentialStoreTest : public testing::Test {
@@ -60,6 +69,15 @@
                           MakeUiCredential("Carl", "P1238C")));
 }
 
+TEST_F(OriginCredentialStoreTest, StoresUnnotifiedSharedCredentials) {
+  store()->SaveUnnotifiedSharedCredentials(
+      {CreateTestPasswordForm(1), CreateTestPasswordForm(2)});
+
+  EXPECT_THAT(
+      store()->GetUnnotifiedSharedCredentials(),
+      ElementsAre(CreateTestPasswordForm(1), CreateTestPasswordForm(2)));
+}
+
 TEST_F(OriginCredentialStoreTest, StoresOnlyNormalizedOrigins) {
   store()->SaveCredentials(
       {MakeUiCredential("Berta", "30948", kExampleSite),
diff --git a/components/performance_manager/BUILD.gn b/components/performance_manager/BUILD.gn
index e7b64c25..9aefc84 100644
--- a/components/performance_manager/BUILD.gn
+++ b/components/performance_manager/BUILD.gn
@@ -166,6 +166,7 @@
     "public/render_process_host_proxy.h",
     "public/resource_attribution/attribution_helpers.h",
     "public/resource_attribution/cpu_measurement_delegate.h",
+    "public/resource_attribution/cpu_proportion_tracker.h",
     "public/resource_attribution/frame_context.h",
     "public/resource_attribution/memory_measurement_delegate.h",
     "public/resource_attribution/page_context.h",
@@ -193,6 +194,7 @@
     "resource_attribution/cpu_measurement_delegate.cc",
     "resource_attribution/cpu_measurement_monitor.cc",
     "resource_attribution/cpu_measurement_monitor.h",
+    "resource_attribution/cpu_proportion_tracker.cc",
     "resource_attribution/frame_context.cc",
     "resource_attribution/graph_change.h",
     "resource_attribution/memory_measurement_delegate.cc",
diff --git a/components/performance_manager/public/resource_attribution/cpu_proportion_tracker.h b/components/performance_manager/public/resource_attribution/cpu_proportion_tracker.h
new file mode 100644
index 0000000..a6c9e87
--- /dev/null
+++ b/components/performance_manager/public/resource_attribution/cpu_proportion_tracker.h
@@ -0,0 +1,92 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_RESOURCE_ATTRIBUTION_CPU_PROPORTION_TRACKER_H_
+#define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_RESOURCE_ATTRIBUTION_CPU_PROPORTION_TRACKER_H_
+
+#include <map>
+#include <optional>
+
+#include "base/functional/callback_forward.h"
+#include "base/functional/callback_helpers.h"
+#include "base/time/time.h"
+#include "components/performance_manager/public/resource_attribution/query_results.h"
+#include "components/performance_manager/public/resource_attribution/resource_contexts.h"
+
+namespace performance_manager::resource_attribution {
+
+// A class that, given a series of consecutive CPUTimeResult measurements, will
+// calculate the proportion of CPU used over a series of consecutive intervals.
+// Any part of the interval that isn't covered by the measurements is counted as
+// 0% CPU.
+class CPUProportionTracker {
+ public:
+  // A callback that's called for every context in the QueryResultMap passed
+  // to StartNextInterval(). If it returns false, the context is ignored.
+  // This can be used when the caller only wants to calculate the proportion
+  // for a subset of results from a query, to avoid making a filtered copy of
+  // the QueryResultMap every interval.
+  using ContextFilterCallback =
+      base::RepeatingCallback<bool(const ResourceContext&)>;
+
+  explicit CPUProportionTracker(
+      ContextFilterCallback context_filter = base::NullCallback());
+  ~CPUProportionTracker();
+
+  CPUProportionTracker(const CPUProportionTracker&) = delete;
+  CPUProportionTracker operator=(const CPUProportionTracker&) = delete;
+
+  // Starts tracking the proportion of CPU. Must be called exactly once before
+  // calling StartNextInterval(). `results` is the result of a CPU query taken
+  // at `time`. Saves CPUTimeResult::cumulative_cpu for each context in
+  // `results` as a baseline of CPU used before the start of the interval.
+  void StartFirstInterval(base::TimeTicks time, const QueryResultMap& results);
+
+  // Calculates the proportion of CPU used by all contexts in `results` since
+  // the last call to StartFirstInterval() or StartNextInterval(). `results` is
+  // the result of a CPU query taken at `time`.
+  //
+  // Returns a map from ResourceContext to CPU time used
+  // (CPUTimeResult::cumulative_cpu) as a proportion of the interval duration.
+  // Since the CPU time can include processes running simultaneously on multiple
+  // cores, this can exceed 100%. It's roughly in the range 0% to
+  // SysInfo::NumberOfProcessors() * 100%, the same scale as
+  // ProcessMetrics::GetPlatformIndependentCPUUsage().
+  //
+  // If the context's lifetime (from CPUTimeResult::start_time to
+  // ResultMetadata::measurement_time) doesn't cover the entire interval, any
+  // part that isn't covered is counted as 0%.
+  //
+  // If the context's `start_time` is before the start of the interval, the
+  // part of its `cumulative_cpu` that came before the interval start is
+  // excluded. If this context wasn't seen in the last call to
+  // StartFirstInterval() or StartNextInterval(), it isn't possible to know how
+  // much to exclude, so the context won't be included in the results until the
+  // next interval.
+  std::map<ResourceContext, double> StartNextInterval(
+      base::TimeTicks time,
+      const QueryResultMap& results);
+
+  // Clears all state. After calling this StartFirstInterval() must be called
+  // again to start a new set of intervals.
+  void Stop();
+
+  // Returns true iff StartFirstInterval() was called and Stop() was not.
+  bool IsTracking() const;
+
+ private:
+  // Last time CPU measurements were taken (for calculating the total length of
+  // a measurement interval).
+  std::optional<base::TimeTicks> last_measurement_time_;
+
+  // A map caching the most recent measurements for each context.
+  QueryResultMap cached_cpu_measurements_;
+
+  // If not null, called for each context passed to StartNextInterval().
+  ContextFilterCallback context_filter_;
+};
+
+}  // namespace performance_manager::resource_attribution
+
+#endif  // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_RESOURCE_ATTRIBUTION_CPU_PROPORTION_TRACKER_H_
diff --git a/components/performance_manager/resource_attribution/cpu_measurement_monitor_unittest.cc b/components/performance_manager/resource_attribution/cpu_measurement_monitor_unittest.cc
index f096ca8..f299985d 100644
--- a/components/performance_manager/resource_attribution/cpu_measurement_monitor_unittest.cc
+++ b/components/performance_manager/resource_attribution/cpu_measurement_monitor_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <map>
 #include <memory>
+#include <optional>
 #include <utility>
 #include <vector>
 
@@ -30,6 +31,7 @@
 #include "components/performance_manager/public/graph/process_node.h"
 #include "components/performance_manager/public/performance_manager.h"
 #include "components/performance_manager/public/resource_attribution/cpu_measurement_delegate.h"
+#include "components/performance_manager/public/resource_attribution/cpu_proportion_tracker.h"
 #include "components/performance_manager/public/resource_attribution/query_results.h"
 #include "components/performance_manager/public/resource_attribution/resource_contexts.h"
 #include "components/performance_manager/test_support/graph_test_harness.h"
@@ -53,9 +55,11 @@
 
 using ::testing::AllOf;
 using ::testing::Conditional;
+using ::testing::Contains;
 using ::testing::Field;
 using ::testing::IsEmpty;
 using ::testing::Not;
+using ::testing::Pair;
 using ::testing::VariantWith;
 
 constexpr base::TimeDelta kTimeBetweenMeasurements = base::Minutes(5);
@@ -138,6 +142,17 @@
     current_measurements_ = cpu_monitor_.UpdateAndGetCPUMeasurements();
   }
 
+  // Helper to get the most recent output of `cpu_monitor_` and convert to a
+  // QueryResultMap which CPUProportionTracker expects.
+  QueryResultMap GetCPUQueryResults() {
+    QueryResultMap results;
+    for (const auto& [context, cpu_time_result] :
+         cpu_monitor_.UpdateAndGetCPUMeasurements()) {
+      results[context] = QueryResults{cpu_time_result};
+    }
+    return results;
+  }
+
   // GMock matcher expecting that a given QueryResult variant contains a
   // CPUTimeResult with cumulative_cpu `last_measurements_[context] +
   // expected_delta`. That is, since the last time `context` was tested, expect
@@ -1237,6 +1252,290 @@
                                      kTimeBetweenMeasurements / 2)));
 }
 
+// Tests the CPUProportionTracker helper class.
+TEST_F(ResourceAttrCPUMonitorTest, CPUProportionTracker) {
+  // Since the CPU monitor has trouble measuring processes on exit, create some
+  // long-lived processes. The test will create and delete frames in a process
+  // to measure contexts that are added and removed during measurement periods.
+  // The frames will not share the process so they get all the process CPU.
+  auto create_process = [&](double cpu_usage) {
+    TestNodeWrapper<ProcessNodeImpl> renderer = CreateMockCPURenderer();
+    SetProcessId(renderer.get());
+    SetProcessCPUUsage(renderer.get(), cpu_usage);
+    return renderer;
+  };
+  const TestNodeWrapper<ProcessNodeImpl> process_90 = create_process(0.9);
+  const TestNodeWrapper<ProcessNodeImpl> process_80 = create_process(0.8);
+  const TestNodeWrapper<ProcessNodeImpl> process_70 = create_process(0.7);
+  const TestNodeWrapper<ProcessNodeImpl> process_60 = create_process(0.6);
+  const TestNodeWrapper<ProcessNodeImpl> process_50 = create_process(0.5);
+  const TestNodeWrapper<ProcessNodeImpl> process_40 = create_process(0.4);
+  const TestNodeWrapper<PageNodeImpl> page_node = CreateNode<PageNodeImpl>();
+
+  // Create a tracker that only looks at frames, so that the results are easier
+  // to compare.
+  CPUProportionTracker proportion_tracker(
+      base::BindRepeating(&ContextIs<FrameContext>));
+  StartMonitoring();
+
+  std::map<ResourceContext, double> expected_results;
+
+  // Context that existed before CPUProportionTracker started.
+  // Uses 50% CPU for the entire interval = 0.5.
+  std::optional<TestNodeWrapper<FrameNodeImpl>> existing_frame1 =
+      CreateFrameNodeAutoId(process_50.get(), page_node.get());
+  expected_results[existing_frame1.value()->GetResourceContext()] = 0.5;
+
+  // Another context that existed before CPUProportionTracker, and will exit
+  // half-way through the interval.
+  // Uses 40% CPU for half the interval = 0.2.
+  std::optional<TestNodeWrapper<FrameNodeImpl>> existing_frame2 =
+      CreateFrameNodeAutoId(process_40.get(), page_node.get());
+  expected_results[existing_frame2.value()->GetResourceContext()] = 0.2;
+
+  task_env().FastForwardBy(kTimeBetweenMeasurements);
+
+  // Test the first interval, where the CPUProportionTracker has no history.
+  proportion_tracker.StartFirstInterval(base::TimeTicks::Now(),
+                                        GetCPUQueryResults());
+
+  // Context exists for entire interval.
+  // Uses 90% CPU for entire interval = 0.9.
+  std::optional<TestNodeWrapper<FrameNodeImpl>> frame1 =
+      CreateFrameNodeAutoId(process_90.get(), page_node.get());
+  expected_results[frame1.value()->GetResourceContext()] = 0.9;
+
+  // Context exists at start of interval, destroyed half-way through.
+  // Uses 80% CPU for half the interval = 0.4.
+  std::optional<TestNodeWrapper<FrameNodeImpl>> frame2 =
+      CreateFrameNodeAutoId(process_80.get(), page_node.get());
+  expected_results[frame2.value()->GetResourceContext()] = 0.4;
+
+  task_env().FastForwardBy(kTimeBetweenMeasurements / 2);
+  const auto half_first_interval = base::TimeTicks::Now();
+  frame2.reset();
+  existing_frame2.reset();
+
+  // Context created half-way through measurement interval.
+  // Uses 70% CPU for half the interval = 0.35.
+  const TestNodeWrapper<FrameNodeImpl> frame3 =
+      CreateFrameNodeAutoId(process_70.get(), page_node.get());
+  expected_results[frame3->GetResourceContext()] = 0.35;
+
+  // Context created half-way through measurement interval, destroyed 3/4 of the
+  // way through.
+  // Uses 60% CPU for 1/4 of the interval = 0.15.
+  std::optional<TestNodeWrapper<FrameNodeImpl>> frame4 =
+      CreateFrameNodeAutoId(process_60.get(), page_node.get());
+  expected_results[frame4.value()->GetResourceContext()] = 0.15;
+
+  task_env().FastForwardBy(kTimeBetweenMeasurements / 4);
+  frame4.reset();
+
+  // Destroy existing_frame1 at end of interval. Should still count as existing
+  // for the whole interval since this is the same tick as the measurement.
+  task_env().FastForwardBy(kTimeBetweenMeasurements / 4);
+  const auto existing_frame1_context =
+      existing_frame1.value()->GetResourceContext();
+  existing_frame1.reset();
+
+  EXPECT_EQ(expected_results,
+            proportion_tracker.StartNextInterval(base::TimeTicks::Now(),
+                                                 GetCPUQueryResults()));
+
+  // Make sure the same scenarios also work for a second interval, where
+  // CPUProportionTracker has history.
+  std::map<ResourceContext, double> expected_results2;
+
+  // existing_frame1 existed at start of interval so is included, but has no CPU
+  // because it was destroyed on that tick.
+  expected_results2[existing_frame1_context] = 0.0;
+
+  // frame3 existed before the interval.
+  // Uses 70% CPU for the entire interval = 0.7.
+  expected_results2[frame3->GetResourceContext()] = 0.7;
+
+  // New context created at start of interval.
+  // Uses 80% CPU for the entire interval = 0.8.
+  const TestNodeWrapper<FrameNodeImpl> frame5 =
+      CreateFrameNodeAutoId(process_80.get(), page_node.get());
+  expected_results2[frame5->GetResourceContext()] = 0.8;
+
+  // frame1 exists at start of interval, destroyed half-way through.
+  // Uses 90% CPU for half the interval = 0.45.
+  expected_results2[frame1.value()->GetResourceContext()] = 0.45;
+
+  task_env().FastForwardBy(kTimeBetweenMeasurements / 2);
+  frame1.reset();
+
+  // New context created half-way through measurement interval.
+  // Uses 60% CPU for half the interval = 0.3.
+  const TestNodeWrapper<FrameNodeImpl> frame6 =
+      CreateFrameNodeAutoId(process_60.get(), page_node.get());
+  expected_results2[frame6->GetResourceContext()] = 0.3;
+
+  // New context created half-way through measurement interval, destroyed 3/4 of
+  // the way through. Uses 50% CPU for 1/4 of the interval = 0.125.
+  std::optional<TestNodeWrapper<FrameNodeImpl>> frame7 =
+      CreateFrameNodeAutoId(process_50.get(), page_node.get());
+  expected_results2[frame7.value()->GetResourceContext()] = 0.125;
+
+  task_env().FastForwardBy(kTimeBetweenMeasurements / 4);
+  frame7.reset();
+
+  task_env().FastForwardBy(kTimeBetweenMeasurements / 4);
+
+  // Fake that the result included a node with `start_time` during the first
+  // interval, which CPUProportionTracker didn't see during that interval. This
+  // can happen in production if a WorkerNode that existed at `start_time` is
+  // added to a PageNode later, moving the page's `start_time` back.
+  // Since there's no baseline for the node, it shouldn't be included yet.
+  TestNodeWrapper<FrameNodeImpl> frame8 =
+      CreateFrameNodeAutoId(process_40.get(), page_node.get());
+  auto add_fake_result = [&](QueryResultMap results,
+                             base::TimeTicks measurement_time) {
+    results[frame8->GetResourceContext()] = QueryResults{CPUTimeResult{
+        .metadata = {.measurement_time = measurement_time},
+        .start_time = half_first_interval,
+        .cumulative_cpu = (measurement_time - half_first_interval) * 0.4,
+    }};
+    return results;
+  };
+  EXPECT_EQ(expected_results2,
+            proportion_tracker.StartNextInterval(
+                base::TimeTicks::Now(),
+                add_fake_result(GetCPUQueryResults(), base::TimeTicks::Now())));
+
+  // Third interval. The fake `frame8` should now be included using 40% CPU for
+  // the entire interval.
+  task_env().FastForwardBy(kTimeBetweenMeasurements);
+  EXPECT_THAT(
+      proportion_tracker.StartNextInterval(
+          base::TimeTicks::Now(),
+          add_fake_result(GetCPUQueryResults(), base::TimeTicks::Now())),
+      Contains(Pair(frame8->GetResourceContext(), 0.4)));
+}
+
+// Tests that multiple CPUProportionTrackers with different schedules are
+// independent. Also tests trackers with and without a context filter.
+TEST_F(ResourceAttrCPUMonitorTest, MultipleCPUProportionTrackers) {
+  MockMultiplePagesWithMultipleProcessesGraph mock_graph(graph());
+  SetProcessCPUUsage(mock_graph.process.get(), 1.0);
+  SetProcessCPUUsage(mock_graph.other_process.get(), 1.0);
+
+  // Helper to return expected results for all nodes in `mock_graph`.
+  auto get_all_expected_results = [&](double process_cpu) {
+    // `other_process` is fixed at 100%.
+    const double other_process_cpu = 1.0;
+    // `frame` and `other_frame` get 1/2 of `process`.
+    const double frame_cpu = process_cpu / 2;
+    const double other_frame_cpu = process_cpu / 2;
+    // `child_frame` gets all of `other_process`.
+    const double child_frame_cpu = other_process_cpu;
+
+    return std::map<ResourceContext, double>{
+        {mock_graph.process->GetResourceContext(), process_cpu},
+        {mock_graph.other_process->GetResourceContext(), other_process_cpu},
+        {mock_graph.frame->GetResourceContext(), frame_cpu},
+        {mock_graph.other_frame->GetResourceContext(), other_frame_cpu},
+        {mock_graph.child_frame->GetResourceContext(), child_frame_cpu},
+        // `page` contains only `frame`.
+        {mock_graph.page->GetResourceContext(), frame_cpu},
+        // `other_page` contains `other_frame` and `child_frame`.
+        {mock_graph.other_page->GetResourceContext(),
+         other_frame_cpu + child_frame_cpu},
+        // `browser_process` is fixed at 100%.
+        {mock_graph.browser_process->GetResourceContext(), 1.0},
+    };
+  };
+
+  // T = 0
+  StartMonitoring();
+
+  // Tracker that watches all contexts, with a 1 minute interval.
+  CPUProportionTracker all_tracker;
+  all_tracker.StartFirstInterval(base::TimeTicks::Now(), GetCPUQueryResults());
+
+  // T = 15s
+  // `process` CPU drops to 50%.
+  task_env().FastForwardBy(base::Seconds(15));
+  SetProcessCPUUsage(mock_graph.process.get(), 0.5);
+
+  // Tracker that watches only processes. It starts 15 seconds later, with a 30
+  // second interval.
+  CPUProportionTracker process_tracker(
+      base::BindRepeating(&ContextIs<ProcessContext>));
+  process_tracker.StartFirstInterval(base::TimeTicks::Now(),
+                                     GetCPUQueryResults());
+
+  // `other_process` and `browser_process` CPU are fixed at 100%. `process` CPU
+  // will vary.
+  std::map<ResourceContext, double> expected_process_results{
+      {mock_graph.other_process->GetResourceContext(), 1.0},
+      {mock_graph.browser_process->GetResourceContext(), 1.0},
+  };
+
+  // T = 30s
+  // `process` CPU drops to 40%.
+  task_env().FastForwardBy(base::Seconds(15));
+  SetProcessCPUUsage(mock_graph.process.get(), 0.4);
+
+  // T = 45s
+  // End of `process_tracker` 1st interval.
+  task_env().FastForwardBy(base::Seconds(15));
+
+  // `process` used 50% CPU for first half, 40% for second half.
+  expected_process_results[mock_graph.process->GetResourceContext()] =
+      0.5 / 2 + 0.4 / 2;
+  EXPECT_EQ(expected_process_results,
+            process_tracker.StartNextInterval(base::TimeTicks::Now(),
+                                              GetCPUQueryResults()));
+
+  // T = 60s
+  // End of `all_tracker` 1st interval.
+  task_env().FastForwardBy(base::Seconds(15));
+
+  // `process` used 100% CPU for 1/4, 50% for 1/4, 40% for 1/2.
+  EXPECT_EQ(get_all_expected_results(1.0 / 4 + 0.5 / 4 + 0.4 / 2),
+            all_tracker.StartNextInterval(base::TimeTicks::Now(),
+                                          GetCPUQueryResults()));
+
+  // T = 75s
+  // End of `process_tracker` 2nd interval.
+  task_env().FastForwardBy(base::Seconds(15));
+
+  // `process` used 40% CPU for whole interval.
+  expected_process_results[mock_graph.process->GetResourceContext()] = 0.4;
+  EXPECT_EQ(expected_process_results,
+            process_tracker.StartNextInterval(base::TimeTicks::Now(),
+                                              GetCPUQueryResults()));
+
+  // T = 90s
+  // `process` CPU returns to 100%.
+  task_env().FastForwardBy(base::Seconds(15));
+  SetProcessCPUUsage(mock_graph.process.get(), 1.0);
+
+  // T = 105s
+  // End of `process_tracker` 3rd interval.
+  task_env().FastForwardBy(base::Seconds(15));
+
+  // `process` used 40% CPU for first half, 100% for second half.
+  expected_process_results[mock_graph.process->GetResourceContext()] =
+      0.4 / 2 + 1.0 / 2;
+  EXPECT_EQ(expected_process_results,
+            process_tracker.StartNextInterval(base::TimeTicks::Now(),
+                                              GetCPUQueryResults()));
+
+  // T = 120s
+  // End of `all_tracker` 2nd interval.
+  task_env().FastForwardBy(base::Seconds(15));
+
+  // `process` used 40% of CPU for first half, 100% for second half.
+  EXPECT_EQ(get_all_expected_results(0.4 / 2 + 1.0 / 2),
+            all_tracker.StartNextInterval(base::TimeTicks::Now(),
+                                          GetCPUQueryResults()));
+}
+
 // A test that creates real processes, to verify that measurement works with the
 // timing of real node creation.
 class ResourceAttrCPUMonitorTimingTest : public PerformanceManagerTestHarness {
diff --git a/components/performance_manager/resource_attribution/cpu_proportion_tracker.cc b/components/performance_manager/resource_attribution/cpu_proportion_tracker.cc
new file mode 100644
index 0000000..ee0fe4cf
--- /dev/null
+++ b/components/performance_manager/resource_attribution/cpu_proportion_tracker.cc
@@ -0,0 +1,167 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/performance_manager/public/resource_attribution/cpu_proportion_tracker.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "base/check.h"
+#include "base/functional/callback.h"
+#include "base/types/optional_ref.h"
+
+namespace performance_manager::resource_attribution {
+
+CPUProportionTracker::CPUProportionTracker(ContextFilterCallback context_filter)
+    : context_filter_(std::move(context_filter)) {}
+
+CPUProportionTracker::~CPUProportionTracker() = default;
+
+void CPUProportionTracker::StartFirstInterval(base::TimeTicks time,
+                                              const QueryResultMap& results) {
+  CHECK(!last_measurement_time_.has_value());
+  CHECK(cached_cpu_measurements_.empty());
+  last_measurement_time_ = time;
+  cached_cpu_measurements_ = results;
+}
+
+std::map<ResourceContext, double> CPUProportionTracker::StartNextInterval(
+    base::TimeTicks time,
+    const QueryResultMap& results) {
+  CHECK(last_measurement_time_.has_value());
+  const base::TimeTicks interval_start = last_measurement_time_.value();
+  const base::TimeDelta measurement_interval = time - interval_start;
+  last_measurement_time_ = time;
+  if (measurement_interval.is_zero()) {
+    // No time passed to measure. Ignore the results to avoid division by zero.
+    return {};
+  }
+  CHECK(measurement_interval.is_positive());
+
+  // Swap a new measurement into `cached_cpu_measurements_`, storing the
+  // previous contents in `previous_measurements`.
+  QueryResultMap previous_measurements =
+      std::exchange(cached_cpu_measurements_, results);
+
+  std::map<ResourceContext, double> cpu_usage_map;
+  for (const auto& [context, query_result] : cached_cpu_measurements_) {
+    if (!context_filter_.is_null() && !context_filter_.Run(context)) {
+      continue;
+    }
+    base::optional_ref<const CPUTimeResult> result =
+        AsResult<CPUTimeResult>(query_result);
+    if (!result.has_value()) {
+      continue;
+    }
+
+    // Let time A be the last time StartNextInterval() was called, or the time
+    // when StartFirstInterval() was called if this is the first one. The
+    // results seen at that time are saved in `previous_measurements`.
+    //
+    // Let time B be current time. (`measurement_interval` is A..B.)
+    //
+    // There are 5 cases:
+    //
+    // 1. The context was created at time C, between A and B. (It will not be
+    // found in `previous_measurements`).
+    //
+    // This snapshot should include 0% CPU for time A..C, and the measured % of
+    // CPU for time C..B.
+    //
+    // A    C         B
+    // |----+---------|
+    // | 0% |   X%    |
+    //
+    // CPU(C..B) is `result.cumulative_cpu`.
+    // `result.start_time` is C.
+    // `result.metadata.measurement_time` is B.
+    //
+    // 2. The context existed for the entire duration A..B.
+    //
+    // This snapshot should include the measured % of CPU for the whole time
+    // A..B.
+    //
+    // A              B
+    // |--------------|
+    // |      X%      |
+    //
+    // CPU(A..B) is `result.cumulative_cpu -
+    // previous_measurements[context].cumulative_cpu`.
+    // `result.start_time` <= A.
+    // `result.metadata.measurement_time` is B.
+    //
+    // 3. Context created before time A, exited at time D, between A and B.
+    //
+    // The snapshot should include the measured % of CPU for time A..D, and 0%
+    // CPU for time D..B.
+    //
+    // A         D    B
+    // |---------+----|
+    // |    X%   | 0% |
+    //
+    // CPU(A..D) is `result.cumulative_cpu -
+    // previous_measurements[context].cumulative_cpu`.
+    // `result.start_time` <= A.
+    // `result.metadata.measurement_time` is D.
+    //
+    // 4. Context created at time C and exited at time D, both between A and B.
+    // (context is not found in `previous_measurements`.
+    // `result.cumulative_cpu` ends at time D, which is
+    // `result.metadata.measurement_time`.)
+    //
+    // The snapshot should include the measured % of CPU for time C..D, and 0%
+    // CPU for the rest.
+    //
+    // A    C    D    B
+    // |----+----+----|
+    // | 0% | X% | 0% |
+    //
+    // CPU(C..D) is `result.cumulative_cpu`.
+    // `result.start_time` is C.
+    // `result.metadata.measurement_time` is D.
+    //
+    // 5. Context exited before time A. (This is an old cached result.)
+    //
+    // The snapshot should not include this context at all.
+    //
+    // C    D A              B
+    // |----| |--------------|
+    // | X% | |      0%      |
+    // `result.start_time` <= `result.metadata.measurement_time` <= A
+    if (result->metadata.measurement_time < interval_start) {
+      // Case 5.
+      continue;
+    }
+    base::TimeDelta current_cpu = result->cumulative_cpu;
+    if (result->start_time < interval_start) {
+      // Case 2 or 3.
+      const auto it = previous_measurements.find(context);
+      base::optional_ref<const CPUTimeResult> previous_result =
+          it == previous_measurements.end()
+              ? std::nullopt
+              : AsResult<CPUTimeResult>(it->second);
+      if (!previous_result.has_value()) {
+        // No baseline to know how much of the context's CPU came before the
+        // interval. Skip it.
+        continue;
+      }
+      current_cpu -= previous_result->cumulative_cpu;
+    }
+    CHECK(!current_cpu.is_negative());
+    cpu_usage_map.emplace(context, current_cpu / measurement_interval);
+  }
+  return cpu_usage_map;
+}
+
+void CPUProportionTracker::Stop() {
+  CHECK(last_measurement_time_.has_value());
+  last_measurement_time_.reset();
+  cached_cpu_measurements_.clear();
+}
+
+bool CPUProportionTracker::IsTracking() const {
+  return last_measurement_time_.has_value();
+}
+
+}  // namespace performance_manager::resource_attribution
diff --git a/components/performance_manager/user_tuning/prefs_unittest.cc b/components/performance_manager/user_tuning/prefs_unittest.cc
index 3842fb14..28a85b05 100644
--- a/components/performance_manager/user_tuning/prefs_unittest.cc
+++ b/components/performance_manager/user_tuning/prefs_unittest.cc
@@ -10,14 +10,14 @@
 
 namespace performance_manager::user_tuning::prefs {
 
-class HighEfficiencyModePrefMigrationTest : public ::testing::Test {
+class MemorySaverModePrefMigrationTest : public ::testing::Test {
  public:
   void SetUp() override { RegisterLocalStatePrefs(pref_service_.registry()); }
 
   TestingPrefServiceSimple pref_service_;
 };
 
-TEST_F(HighEfficiencyModePrefMigrationTest, NoChangeToUserSetNewPref) {
+TEST_F(MemorySaverModePrefMigrationTest, NoChangeToUserSetNewPref) {
   // The old pref is set by the user, but so is the new pref so no migration
   // should happen.
   pref_service_.SetBoolean(kMemorySaverModeEnabled, true);
@@ -34,7 +34,7 @@
   EXPECT_FALSE(pref_service_.GetBoolean(kMemorySaverModeEnabled));
 }
 
-TEST_F(HighEfficiencyModePrefMigrationTest, BothPrefsDefaultNoMigration) {
+TEST_F(MemorySaverModePrefMigrationTest, BothPrefsDefaultNoMigration) {
   // Simulate that the default enum state value is not "disabled"
   pref_service_.SetDefaultPrefValue(kMemorySaverModeState, base::Value(1));
 
@@ -52,7 +52,7 @@
             static_cast<int>(MemorySaverModeState::kEnabled));
 }
 
-TEST_F(HighEfficiencyModePrefMigrationTest,
+TEST_F(MemorySaverModePrefMigrationTest,
        MigrateDefaultNewPrefUserSetOldPrefEnabled) {
   // Set the old pref as-if set by the user.
   pref_service_.SetBoolean(kMemorySaverModeEnabled, true);
@@ -76,7 +76,7 @@
   EXPECT_FALSE(pref_service_.GetBoolean(kMemorySaverModeEnabled));
 }
 
-TEST_F(HighEfficiencyModePrefMigrationTest,
+TEST_F(MemorySaverModePrefMigrationTest,
        MigrateDefaultNewPrefUserSetOldPrefDisabled) {
   // Set the old pref as-if set by the user.
   pref_service_.SetBoolean(kMemorySaverModeEnabled, false);
diff --git a/components/permissions/android/java/src/org/chromium/components/permissions/BluetoothChooserDialog.java b/components/permissions/android/java/src/org/chromium/components/permissions/BluetoothChooserDialog.java
index 418ec38..ce75ac72 100644
--- a/components/permissions/android/java/src/org/chromium/components/permissions/BluetoothChooserDialog.java
+++ b/components/permissions/android/java/src/org/chromium/components/permissions/BluetoothChooserDialog.java
@@ -33,6 +33,7 @@
 import org.chromium.components.omnibox.OmniboxUrlEmphasizer;
 import org.chromium.content_public.browser.bluetooth.BluetoothChooserEvent;
 import org.chromium.ui.base.WindowAndroid;
+import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.permissions.PermissionCallback;
 import org.chromium.ui.text.NoUnderlineClickableSpan;
 import org.chromium.ui.text.SpanApplier;
@@ -440,7 +441,8 @@
     }
 
     @CalledByNative
-    private static BluetoothChooserDialog create(
+    @VisibleForTesting
+    public static BluetoothChooserDialog create(
             WindowAndroid windowAndroid,
             String origin,
             int securityLevel,
@@ -452,6 +454,19 @@
             // the dialog.
             return null;
         }
+
+        // Avoid showing the chooser when ModalDialogManager indicates that
+        // tab-modal or app-modal dialogs are suspended.
+        // TODO(crbug.com/1511004): Integrate BluetoothChooserDialog with
+        // ModalDialogManager.
+        ModalDialogManager modalDialogManager = windowAndroid.getModalDialogManager();
+        if (modalDialogManager != null
+                && (modalDialogManager.isSuspended(ModalDialogManager.ModalDialogType.TAB)
+                        || modalDialogManager.isSuspended(
+                                ModalDialogManager.ModalDialogType.APP))) {
+            return null;
+        }
+
         BluetoothChooserDialog dialog =
                 new BluetoothChooserDialog(
                         windowAndroid,
diff --git a/components/permissions/permission_request.cc b/components/permissions/permission_request.cc
index 824a151..4d07c017 100644
--- a/components/permissions/permission_request.cc
+++ b/components/permissions/permission_request.cc
@@ -282,6 +282,10 @@
 }
 #endif
 
+std::optional<std::u16string> PermissionRequest::GetAllowAlwaysText() const {
+  return std::nullopt;
+}
+
 bool PermissionRequest::ShouldUseTwoOriginPrompt() const {
   return request_type() == RequestType::kStorageAccess &&
          base::FeatureList::IsEnabled(
diff --git a/components/permissions/permission_request.h b/components/permissions/permission_request.h
index 4ae1ca29..bbbe227 100644
--- a/components/permissions/permission_request.h
+++ b/components/permissions/permission_request.h
@@ -116,6 +116,12 @@
   virtual std::u16string GetMessageTextFragment() const;
 #endif
 
+  // Returns the text to be used in the "allow always" button of the
+  // permission prompt.
+  // If not provided, the generic text for this button will be used instead.
+  // The default implementation returns std::nullopt (ie, use generic text).
+  virtual std::optional<std::u16string> GetAllowAlwaysText() const;
+
   // Whether the request was initiated by the user clicking on the permission
   // element.
   bool IsEmbeddedPermissionElementInitiated() const;
diff --git a/components/permissions_strings.grdp b/components/permissions_strings.grdp
index 8538d4c..54778c8 100644
--- a/components/permissions_strings.grdp
+++ b/components/permissions_strings.grdp
@@ -345,6 +345,9 @@
     <message name="IDS_SMART_CARD_PERMISSION_PROMPT" desc="Text on dialog that asks the user for permission to access a smart card reader device and the card inserted in it (or presented to it, if contactless).">
       Control <ph name="ReaderName">$1<ex>HID Omnikey</ex></ph> and gain access to the smart card accessible to it?
     </message>
+    <message name="IDS_SMART_CARD_PERMISSION_ALWAYS_ALLOW" desc="Label on button to always allow access to this smart card reader and any card inserted in (or presented to) it.">
+      Always allow, with any card
+    </message>
   </if>
 
   <!-- Quota messages -->
diff --git a/components/permissions_strings_grdp/IDS_SMART_CARD_PERMISSION_ALWAYS_ALLOW.png.sha1 b/components/permissions_strings_grdp/IDS_SMART_CARD_PERMISSION_ALWAYS_ALLOW.png.sha1
new file mode 100644
index 0000000..b33a09c
--- /dev/null
+++ b/components/permissions_strings_grdp/IDS_SMART_CARD_PERMISSION_ALWAYS_ALLOW.png.sha1
@@ -0,0 +1 @@
+3e0e67dcb269c255fe09bd916423511c60eb9d10
\ No newline at end of file
diff --git a/components/policy/BUILD.gn b/components/policy/BUILD.gn
index 0d0b5630..d34f2a7f 100644
--- a/components/policy/BUILD.gn
+++ b/components/policy/BUILD.gn
@@ -26,7 +26,6 @@
 gen_policy_templates_linux = is_linux || is_chromeos
 gen_policy_templates_android = is_android
 gen_policy_templates_mac = is_mac
-gen_policy_templates_chromeos = is_chromeos_ash
 gen_policy_templates_ios = is_ios
 
 # The zip file is grabbed from the Windows build right now.
@@ -36,7 +35,6 @@
 if (gen_policy_templates_zip) {
   gen_policy_templates_common = true
   gen_policy_templates_win = true
-  gen_policy_templates_chromeos = true
 }
 
 if (is_mac) {
@@ -203,27 +201,6 @@
       ]
     }
   }
-  if (gen_policy_templates_chromeos) {
-    outputs += policy_templates_chromeos_outputs
-    args += [
-      "--chromeos_adml",
-      rebase_path(policy_templates_chromeos_adml_path, root_build_dir),
-      "--chromeos_admx",
-      rebase_path(policy_templates_chromeos_admx_path, root_build_dir),
-    ]
-    if (is_chrome_branded) {
-      # Create google.admx and google.adml files that define a common 'Google'
-      # category used for Chrome, Chrome OS and possibly external tools, see
-      # crbug.com/665400.
-      outputs += policy_templates_chromeos_google_outputs
-      args += [
-        "--google_adml",
-        rebase_path(policy_templates_chromeos_google_adml_path, root_build_dir),
-        "--google_admx",
-        rebase_path(policy_templates_chromeos_google_admx_path, root_build_dir),
-      ]
-    }
-  }
   if (gen_policy_templates_ios) {
     outputs += policy_templates_ios_outputs
     args += [
@@ -368,7 +345,7 @@
     output_zip_file = "$root_out_dir/policy_templates.zip"
     script = "tools/make_policy_zip.py"
     inputs = [ version_path ] + policy_templates_win_outputs +
-             policy_templates_chromeos_outputs + policy_templates_common_outputs
+             policy_templates_common_outputs
     outputs = [ output_zip_file ]
     args = [
       "--output",
@@ -393,23 +370,14 @@
       rebase_path(policy_templates_win_adml_path, root_build_dir),
       "--add",
       rebase_path(policy_templates_win_admx_path, root_build_dir),
-      "--add",
-      rebase_path(policy_templates_chromeos_adml_path, root_build_dir),
-      "--add",
-      rebase_path(policy_templates_chromeos_admx_path, root_build_dir),
     ]
     if (is_chrome_branded) {
       inputs += policy_templates_win_google_outputs
-      inputs += policy_templates_chromeos_google_outputs
       args += [
         "--add",
         rebase_path(policy_templates_win_google_adml_path, root_build_dir),
         "--add",
         rebase_path(policy_templates_win_google_admx_path, root_build_dir),
-        "--add",
-        rebase_path(policy_templates_chromeos_google_adml_path, root_build_dir),
-        "--add",
-        rebase_path(policy_templates_chromeos_google_admx_path, root_build_dir),
       ]
     }
     deps = [
diff --git a/components/policy/resources/new_policy_templates/policy.yaml b/components/policy/resources/new_policy_templates/policy.yaml
index 88a118d..d75eb5f 100644
--- a/components/policy/resources/new_policy_templates/policy.yaml
+++ b/components/policy/resources/new_policy_templates/policy.yaml
@@ -116,10 +116,6 @@
 # policy only exists on ChromeOS.
 device_only: false
 
-# Deprecated field, which should only be used for legacy policies that were
-# supported by ChromeAD. No new policy should use this.
-supported_chrome_os_management: ['google_cloud', 'active_directory']
-
 features:
   # Optional field that is `true` by default.
   # Set to False to suppress the policy in the generated
diff --git a/components/policy/resources/policy_templates.gni b/components/policy/resources/policy_templates.gni
index e6fef6c0..855c266 100644
--- a/components/policy/resources/policy_templates.gni
+++ b/components/policy/resources/policy_templates.gni
@@ -144,29 +144,6 @@
       [ "$policy_templates_base_dir/windows/admx/${lang}/google.adml" ]
 }
 
-# Chrome OS outputs.
-policy_templates_chromeos_admx_path =
-    "$policy_templates_base_dir/chromeos/admx/chromeos.admx"
-policy_templates_chromeos_adml_path =
-    "$policy_templates_base_dir/chromeos/admx/\${lang}/chromeos.adml"
-policy_templates_chromeos_outputs = [ policy_templates_chromeos_admx_path ]
-foreach(lang, policy_templates_languages) {
-  policy_templates_chromeos_outputs +=
-      [ "$policy_templates_base_dir/chromeos/admx/${lang}/chromeos.adml" ]
-}
-
-# Additional Chrome OS outputs for branded builds.
-policy_templates_chromeos_google_admx_path =
-    "$policy_templates_base_dir/chromeos/admx/google.admx"
-policy_templates_chromeos_google_adml_path =
-    "$policy_templates_base_dir/chromeos/admx/\${lang}/google.adml"
-policy_templates_chromeos_google_outputs =
-    [ policy_templates_chromeos_google_admx_path ]
-foreach(lang, policy_templates_languages) {
-  policy_templates_chromeos_google_outputs +=
-      [ "$policy_templates_base_dir/chromeos/admx/${lang}/google.adml" ]
-}
-
 # iOS outputs
 policy_templates_ios_app_config_path =
     "$policy_templates_base_dir/ios/appconfig.xml"
diff --git a/components/policy/resources/templates/policy_definitions/ActiveDirectoryManagement/ChromadToCloudMigrationEnabled.yaml b/components/policy/resources/templates/policy_definitions/ActiveDirectoryManagement/ChromadToCloudMigrationEnabled.yaml
index 003c305..fcbb144 100644
--- a/components/policy/resources/templates/policy_definitions/ActiveDirectoryManagement/ChromadToCloudMigrationEnabled.yaml
+++ b/components/policy/resources/templates/policy_definitions/ActiveDirectoryManagement/ChromadToCloudMigrationEnabled.yaml
@@ -25,8 +25,6 @@
 - file://chrome/browser/ash/authpolicy/OWNERS
 schema:
   type: boolean
-supported_chrome_os_management:
-- active_directory
 supported_on:
 - chrome_os:98-114
 tags: []
diff --git a/components/policy/resources/templates/policy_definitions/ActiveDirectoryManagement/DeviceAuthDataCacheLifetime.yaml b/components/policy/resources/templates/policy_definitions/ActiveDirectoryManagement/DeviceAuthDataCacheLifetime.yaml
index c036d80..a3dec12 100644
--- a/components/policy/resources/templates/policy_definitions/ActiveDirectoryManagement/DeviceAuthDataCacheLifetime.yaml
+++ b/components/policy/resources/templates/policy_definitions/ActiveDirectoryManagement/DeviceAuthDataCacheLifetime.yaml
@@ -20,8 +20,6 @@
   maximum: 9999
   minimum: 0
   type: integer
-supported_chrome_os_management:
-- active_directory
 supported_on:
 - chrome_os:73-114
 tags:
diff --git a/components/policy/resources/templates/policy_definitions/ActiveDirectoryManagement/DeviceGpoCacheLifetime.yaml b/components/policy/resources/templates/policy_definitions/ActiveDirectoryManagement/DeviceGpoCacheLifetime.yaml
index 2351852..1472557 100644
--- a/components/policy/resources/templates/policy_definitions/ActiveDirectoryManagement/DeviceGpoCacheLifetime.yaml
+++ b/components/policy/resources/templates/policy_definitions/ActiveDirectoryManagement/DeviceGpoCacheLifetime.yaml
@@ -20,8 +20,6 @@
   maximum: 9999
   minimum: 0
   type: integer
-supported_chrome_os_management:
-- active_directory
 supported_on:
 - chrome_os:73-114
 tags: []
diff --git a/components/policy/resources/templates/policy_definitions/ActiveDirectoryManagement/DeviceKerberosEncryptionTypes.yaml b/components/policy/resources/templates/policy_definitions/ActiveDirectoryManagement/DeviceKerberosEncryptionTypes.yaml
index f74bcba..693a4d1c 100644
--- a/components/policy/resources/templates/policy_definitions/ActiveDirectoryManagement/DeviceKerberosEncryptionTypes.yaml
+++ b/components/policy/resources/templates/policy_definitions/ActiveDirectoryManagement/DeviceKerberosEncryptionTypes.yaml
@@ -36,8 +36,6 @@
   - 1
   - 2
   type: integer
-supported_chrome_os_management:
-- active_directory
 supported_on:
 - chrome_os:66-114
 tags:
diff --git a/components/policy/resources/templates/policy_definitions/ActiveDirectoryManagement/DeviceMachinePasswordChangeRate.yaml b/components/policy/resources/templates/policy_definitions/ActiveDirectoryManagement/DeviceMachinePasswordChangeRate.yaml
index 2d118f5..520735a 100644
--- a/components/policy/resources/templates/policy_definitions/ActiveDirectoryManagement/DeviceMachinePasswordChangeRate.yaml
+++ b/components/policy/resources/templates/policy_definitions/ActiveDirectoryManagement/DeviceMachinePasswordChangeRate.yaml
@@ -20,8 +20,6 @@
   maximum: 9999
   minimum: 0
   type: integer
-supported_chrome_os_management:
-- active_directory
 supported_on:
 - chrome_os:66-114
 tags:
diff --git a/components/policy/resources/templates/policy_definitions/ActiveDirectoryManagement/DeviceUserPolicyLoopbackProcessingMode.yaml b/components/policy/resources/templates/policy_definitions/ActiveDirectoryManagement/DeviceUserPolicyLoopbackProcessingMode.yaml
index 3ef89a3..0d8627c 100644
--- a/components/policy/resources/templates/policy_definitions/ActiveDirectoryManagement/DeviceUserPolicyLoopbackProcessingMode.yaml
+++ b/components/policy/resources/templates/policy_definitions/ActiveDirectoryManagement/DeviceUserPolicyLoopbackProcessingMode.yaml
@@ -32,8 +32,6 @@
   - 1
   - 2
   type: integer
-supported_chrome_os_management:
-- active_directory
 supported_on:
 - chrome_os:66-114
 tags: []
diff --git a/components/policy/resources/templates/policy_definitions/Miscellaneous/InsecureFormsWarningsEnabled.yaml b/components/policy/resources/templates/policy_definitions/Miscellaneous/InsecureFormsWarningsEnabled.yaml
index c5440e2..fc2eae3e 100644
--- a/components/policy/resources/templates/policy_definitions/Miscellaneous/InsecureFormsWarningsEnabled.yaml
+++ b/components/policy/resources/templates/policy_definitions/Miscellaneous/InsecureFormsWarningsEnabled.yaml
@@ -24,5 +24,6 @@
 - chrome.*:86-
 - chrome_os:86-
 - android:86-
+- ios:122-
 tags: []
 type: main
diff --git a/components/policy/test/data/pref_mapping/InsecureFormsWarningsEnabled.json b/components/policy/test/data/pref_mapping/InsecureFormsWarningsEnabled.json
index ea48787d..896bd8f 100644
--- a/components/policy/test/data/pref_mapping/InsecureFormsWarningsEnabled.json
+++ b/components/policy/test/data/pref_mapping/InsecureFormsWarningsEnabled.json
@@ -11,11 +11,21 @@
     ],
     "policy_pref_mapping_tests": [
       {
+        "note": "Default value (no policies set).",
+        "prefs": {
+          "profile.mixed_forms_warnings": {
+            "default_value": true
+          }
+        }
+      },
+      {
         "policies": {
-          "InsecureFormsWarningsEnabled": true
+          "InsecureFormsWarningsEnabled": false
         },
         "prefs": {
-          "profile.mixed_forms_warnings": {}
+          "profile.mixed_forms_warnings": {
+            "value": false
+          }
         }
       }
     ]
diff --git a/components/policy/tools/generate_policy_source.py b/components/policy/tools/generate_policy_source.py
index 7b5545b..67db1ae 100755
--- a/components/policy/tools/generate_policy_source.py
+++ b/components/policy/tools/generate_policy_source.py
@@ -92,8 +92,6 @@
     self.is_deprecated = policy.get('deprecated', False)
     self.is_device_only = policy.get('device_only', False)
     self.per_profile = features.get('per_profile', False)
-    self.supported_chrome_os_management = policy.get(
-        'supported_chrome_os_management', ['active_directory', 'google_cloud'])
     self.schema = policy['schema']
     self.validation_schema = policy.get('validation_schema')
     self.has_enterprise_default = 'default_for_enterprise_users' in policy
@@ -266,20 +264,6 @@
       help='generate header file for policy risk tags',
       metavar='FILE')
   parser.add_argument(
-      '--crospch',
-      '--cros-policy-constants-header',
-      dest='cros_constants_header_path',
-      help='generate header file of policy constants for use in '
-      'Chrome OS',
-      metavar='FILE')
-  parser.add_argument(
-      '--crospcc',
-      '--cros-policy-constants-source',
-      dest='cros_constants_source_path',
-      help='generate source file of policy constants for use in '
-      'Chrome OS',
-      metavar='FILE')
-  parser.add_argument(
       '--chrome-version-file',
       dest='chrome_version_file',
       help='path to src/chrome/VERSION',
@@ -390,18 +374,6 @@
   if target_platform == 'android' and args.app_restrictions_path:
     GenerateFile(args.app_restrictions_path, _WriteAppRestrictions, xml=True)
 
-  # Generated code for Chrome OS (unused in Chromium).
-  if args.cros_constants_header_path:
-    GenerateFile(
-        args.cros_constants_header_path,
-        _WriteChromeOSPolicyConstantsHeader,
-        sorted=True)
-  if args.cros_constants_source_path:
-    GenerateFile(
-        args.cros_constants_source_path,
-        _WriteChromeOSPolicyConstantsSource,
-        sorted=True)
-
   return 0
 
 
@@ -1458,8 +1430,6 @@
 
 #------------------ policy protobufs -------------------------------#
 
-# This code applies to both Active Directory and Google cloud management.
-
 CHROME_SETTINGS_PROTO_HEAD = '''
 syntax = "proto2";
 
@@ -1634,172 +1604,11 @@
   f.write('}\n')
 
 
-#------------------ Chrome OS policy constants header --------------#
-
-# This code applies to Active Directory management only.
-
-
-# Filter for _GetSupportedChromeOSPolicies().
-def _IsSupportedChromeOSPolicy(type, policy):
-  # Filter out unsupported policies.
-  if not policy.is_supported:
-    return False
-  # Filter out device policies if user policies are requested.
-  if type == 'user' and policy.is_device_only:
-    return False
-  # Filter out user policies if device policies are requested.
-  if type == 'device' and not policy.is_device_only:
-    return False
-  # Filter out non-Active-Directory policies.
-  if 'active_directory' not in policy.supported_chrome_os_management:
-    return False
-  return True
-
-
-# Returns a list of supported user and/or device policies by filtering
-# |policies|. |type| may be 'user', 'device' or 'both'.
-def _GetSupportedChromeOSPolicies(policies, type):
-  if (type not in ['user', 'device', 'both']):
-    raise RuntimeError('Unsupported type "%s"' % type)
-
-  return list(filter(partial(_IsSupportedChromeOSPolicy, type), policies))
-
-
-# Returns a list of supported user and/or device |policies| additionally
-# filtered by |protobuf_type|, which may be any of |_GetProtobufTypes|.
-def _GetSupportedChromeOSPoliciesForProtobufType(policies, type, protobuf_type):
-  supported_policies = _GetSupportedChromeOSPolicies(policies, type)
-
-  return [
-      p for p in supported_policies if p.policy_protobuf_type == protobuf_type
-  ]
-
-
 # Returns the list of all policy.policy_protobuf_type strings from |policies|.
 def _GetProtobufTypes():
   return sorted(['Integer', 'Boolean', 'String', 'StringList'])
 
 
-# Writes the definition of an array that contains the pointers to the mutable
-# proto field for each policy in |policies| of the given |protobuf_type|.
-def _WriteChromeOSPolicyAccessHeader(supported_policies, f, protobuf_type):
-  f.write('// Access to the mutable protobuf function of all supported '
-          '%s user\n// policies.\n' % protobuf_type.lower())
-  f.write('struct %sPolicyAccess {\n'
-          '  const char* policy_key;\n'
-          '  bool per_profile;\n'
-          '  enterprise_management::%sPolicyProto* (*mutable_proto_ptr)(\n'
-          '      enterprise_management::CloudPolicySettings* policy);\n'
-          '};\n' % (protobuf_type, protobuf_type))
-  f.write('extern const std::array<%sPolicyAccess, %d> k%sPolicyAccess;\n\n' %
-          (protobuf_type, len(supported_policies), protobuf_type))
-
-
-# Writes policy_constants.h for use in Chrome OS.
-def _WriteChromeOSPolicyConstantsHeader(policies, policy_atomic_groups,
-                                        target_platform, f, risk_tags,
-                                        chunking):
-  f.write('#ifndef __BINDINGS_POLICY_CONSTANTS_H_\n'
-          '#define __BINDINGS_POLICY_CONSTANTS_H_\n\n'
-          '#include <array>\n\n')
-
-  # Forward declarations.
-  supported_user_policies = _GetSupportedChromeOSPolicies(policies, 'user')
-  protobuf_types = _GetProtobufTypes()
-  f.write('namespace enterprise_management {\n' 'class CloudPolicySettings;\n')
-  for protobuf_type in protobuf_types:
-    f.write('class %sPolicyProto;\n' % protobuf_type)
-  f.write('}  // namespace enterprise_management\n\n')
-
-  f.write('namespace policy {\n\n')
-
-  # Policy keys.
-  all_supported_policies = _GetSupportedChromeOSPolicies(policies, 'both')
-  f.write('// Registry key names for user and device policies.\n'
-          'namespace key {\n\n')
-  for policy in all_supported_policies:
-    f.write('extern const char k' + policy.name + '[];\n')
-  f.write('\n}  // namespace key\n\n')
-
-  # Device policy keys.
-  f.write('// NULL-terminated list of device policy registry key names.\n')
-  f.write('extern const char* kDevicePolicyKeys[];\n\n')
-
-  # User policy proto pointers, one struct for each protobuf type.
-  for protobuf_type in protobuf_types:
-    supported_user_policies = _GetSupportedChromeOSPoliciesForProtobufType(
-        policies, 'user', protobuf_type)
-    _WriteChromeOSPolicyAccessHeader(supported_user_policies, f, protobuf_type)
-
-  f.write('}  // namespace policy\n\n'
-          '#endif  // __BINDINGS_POLICY_CONSTANTS_H_\n')
-
-
-#------------------ Chrome OS policy constants source --------------#
-
-
-# Writes an array that contains the pointers to the mutable proto field for each
-# policy in |policies| of the given |protobuf_type|.
-def _WriteChromeOSPolicyAccessSource(supported_policies, f, protobuf_type,
-                                     chunking):
-  f.write('const std::array<%sPolicyAccess, %d> k%sPolicyAccess {{\n' %
-          (protobuf_type, len(supported_policies), protobuf_type))
-  for policy in supported_policies:
-    name = policy.name
-    lowercase_name = name.lower()
-
-    chunk_number = _ChunkNumber(policy.id, chunking)
-    if chunk_number == 0:
-      mutable_proto_ptr = 'policy->mutable_%s()' % lowercase_name
-    else:
-      mutable_proto_ptr = 'policy->mutable_subproto%d()->mutable_%s()' % (
-          chunk_number, lowercase_name)
-
-    f.write('  {key::k%s,\n'
-            '   %s,\n'
-            '   [](em::CloudPolicySettings* policy)\n'
-            '       -> em::%sPolicyProto* {\n'
-            '     return %s;\n'
-            '   }\n'
-            '  },\n' % (name, str(
-                policy.per_profile).lower(), protobuf_type, mutable_proto_ptr))
-  f.write('}};\n\n')
-
-
-# Writes policy_constants.cc for use in Chrome OS.
-def _WriteChromeOSPolicyConstantsSource(policies, policy_atomic_groups,
-                                        target_platform, f, risk_tags,
-                                        chunking):
-  f.write('#include "bindings/cloud_policy.pb.h"\n'
-          '#include "bindings/policy_constants.h"\n\n'
-          'namespace em = enterprise_management;\n\n'
-          'namespace policy {\n\n')
-
-  # Policy keys.
-  all_supported_policies = _GetSupportedChromeOSPolicies(policies, 'both')
-  f.write('namespace key {\n\n')
-  for policy in all_supported_policies:
-    f.write('const char k{name}[] = "{name}";\n'.format(name=policy.name))
-  f.write('\n}  // namespace key\n\n')
-
-  # Device policy keys.
-  supported_device_policies = _GetSupportedChromeOSPolicies(policies, 'device')
-  f.write('const char* kDevicePolicyKeys[] = {\n\n')
-  for policy in supported_device_policies:
-    f.write('  key::k%s,\n' % policy.name)
-  f.write('  nullptr};\n\n')
-
-  # User policy proto pointers, one struct for each protobuf type.
-  protobuf_types = _GetProtobufTypes()
-  for protobuf_type in protobuf_types:
-    supported_user_policies = _GetSupportedChromeOSPoliciesForProtobufType(
-        policies, 'user', protobuf_type)
-    _WriteChromeOSPolicyAccessSource(supported_user_policies, f, protobuf_type,
-                                     chunking)
-
-  f.write('}  // namespace policy\n')
-
-
 #------------------ app restrictions -------------------------------#
 
 
diff --git a/components/policy/tools/generate_policy_source_test.py b/components/policy/tools/generate_policy_source_test.py
index 236966f..87cc43d 100755
--- a/components/policy/tools/generate_policy_source_test.py
+++ b/components/policy/tools/generate_policy_source_test.py
@@ -441,38 +441,6 @@
         self._assertCallsEqual(expected_formatted,
                                mocked_file().write.call_args_list)
 
-  def testWriteChromeOSPolicyConstantsHeader(self):
-    output_path = 'mock_policy_constants_h'
-    with patch('codecs.open', mock_open()) as mocked_file:
-      with codecs.open(output_path, 'w', encoding='utf-8') as f:
-        generate_policy_source._WriteChromeOSPolicyConstantsHeader(
-            self.policies,
-            self.policy_atomic_groups,
-            self.target_platform,
-            f,
-            self.risk_tags,
-            chunking=True,
-        )
-    mocked_file.assert_called_once_with(output_path, 'w', encoding='utf-8')
-    self._assertCallsEqual(test_data.EXPECTED_CROS_POLICY_CONSTANTS_HEADER,
-                           mocked_file().write.call_args_list)
-
-  def testWriteChromeOSPolicyConstantsSource(self):
-    output_path = 'mock_policy_constants_cc'
-    with patch('codecs.open', mock_open()) as mocked_file:
-      with codecs.open(output_path, 'w', encoding='utf-8') as f:
-        generate_policy_source._WriteChromeOSPolicyConstantsSource(
-            self.policies,
-            self.policy_atomic_groups,
-            self.target_platform,
-            f,
-            self.risk_tags,
-            chunking=True,
-        )
-    mocked_file.assert_called_once_with(output_path, 'w', encoding='utf-8')
-    self._assertCallsEqual(test_data.EXPECTED_CROS_POLICY_CONSTANTS_SOURCE,
-                           mocked_file().write.call_args_list)
-
 
   def testWriteAppRestrictions(self):
     output_path = 'app_restrictions_xml'
diff --git a/components/policy/tools/syntax_check_policy_template_json.py b/components/policy/tools/syntax_check_policy_template_json.py
index ab69ccc..1fcc64e 100755
--- a/components/policy/tools/syntax_check_policy_template_json.py
+++ b/components/policy/tools/syntax_check_policy_template_json.py
@@ -234,9 +234,6 @@
 # List of supported metapolicy types.
 METAPOLICY_TYPES = ['merge', 'precedence']
 
-# List of supported chrome os management tags.
-SUPPORTED_CHROME_OS_MANAGEMENT = ['google_cloud', 'active_directory']
-
 # Helper function to determine if a given type defines a key in a dictionary
 # that is used to condition certain backwards compatibility checks.
 def IsKeyDefinedForTypeInDictionary(type, key, key_per_type_dict):
@@ -884,7 +881,6 @@
           'default_for_managed_devices_doc_only',
           'default_policy_level',
           'arc_support',
-          'supported_chrome_os_management',
       ):
         self._PolicyError(f'Unknown key: {key}', policy, key)
 
@@ -1186,31 +1182,6 @@
                           policy, 'features')
 
 
-      # Chrome OS policies may have a non-empty supported_chrome_os_management
-      # list with either 'active_directory' or 'google_cloud' or both.
-      supported_chrome_os_management = self._CheckContains(
-          policy, 'supported_chrome_os_management', list, True)
-      if supported_chrome_os_management is not None:
-        # Must be on Chrome OS.
-        if (supported_on is not None
-            and not any('chrome_os' == str
-                        for str in (supported_platforms +
-                                    (future_on if future_on else [])))):
-          self._PolicyError(
-              '"supported_chrome_os_management" is used for policy that does '
-              'not support Chrome OS.', policy, 'supported_on')
-        # Must be non-empty.
-        if len(supported_chrome_os_management) == 0:
-          self._PolicyError('"supported_chrome_os_management" is empty', policy,
-                            'supported_chrome_os_management')
-        # Must be either 'active_directory' or 'google_cloud'.
-        if (any(str not in SUPPORTED_CHROME_OS_MANAGEMENT
-                for str in supported_chrome_os_management)):
-          self._PolicyError(
-              '"supported_chrome_os_management" contains supported entry.\n'
-              f'Please use one of {SUPPORTED_CHROME_OS_MANAGEMENT}', policy,
-              'supported_chrome_os_management')
-
       # Each policy must have an 'example_value' of appropriate type.
       self._CheckContains(policy, 'example_value',
                           _GetPolicyValueType(policy_type))
diff --git a/components/policy/tools/template_writers/template_formatter.py b/components/policy/tools/template_writers/template_formatter.py
index 58b724e0..cba27c0 100755
--- a/components/policy/tools/template_writers/template_formatter.py
+++ b/components/policy/tools/template_writers/template_formatter.py
@@ -18,7 +18,6 @@
 import policy_template_generator
 
 from writers import adm_writer, adml_writer, admx_writer, \
-                    chromeos_admx_writer, chromeos_adml_writer, \
                     google_admx_writer, google_adml_writer, \
                     android_policy_writer, reg_writer, doc_writer, \
                     doc_atomic_groups_writer , json_writer, plist_writer, \
@@ -56,8 +55,6 @@
     WriterDesc('admx', False, 'utf-16', None, True),
     WriterDesc('google_adml', True, 'utf-8', None, True),
     WriterDesc('google_admx', False, 'utf-8', None, True),
-    WriterDesc('chromeos_adml', True, 'utf-8', None, True),
-    WriterDesc('chromeos_admx', False, 'utf-8', None, True),
     WriterDesc('android_policy', False, 'utf-8', None, False),
     WriterDesc('reg', False, 'utf-16', None, False),
     WriterDesc('doc', True, 'utf-8', None, False),
diff --git a/components/policy/tools/template_writers/test_suite_all.py b/components/policy/tools/template_writers/test_suite_all.py
index d83e122..2f77d58 100755
--- a/components/policy/tools/template_writers/test_suite_all.py
+++ b/components/policy/tools/template_writers/test_suite_all.py
@@ -20,8 +20,6 @@
     import writers.adml_writer_unittest
     import writers.admx_writer_unittest
     import writers.android_policy_writer_unittest
-    import writers.chromeos_adml_writer_unittest
-    import writers.chromeos_admx_writer_unittest
     import writers.doc_writer_unittest
     import writers.google_adml_writer_unittest
     import writers.google_admx_writer_unittest
@@ -40,8 +38,6 @@
         writers.adml_writer_unittest.AdmlWriterUnittest,
         writers.admx_writer_unittest.AdmxWriterUnittest,
         writers.android_policy_writer_unittest.AndroidPolicyWriterUnittest,
-        writers.chromeos_adml_writer_unittest.ChromeOsAdmlWriterUnittest,
-        writers.chromeos_admx_writer_unittest.ChromeOsAdmxWriterUnittest,
         writers.doc_writer_unittest.DocWriterUnittest,
         writers.google_adml_writer_unittest.GoogleAdmlWriterUnittest,
         writers.google_admx_writer_unittest.GoogleAdmxWriterUnittest,
diff --git a/components/policy/tools/template_writers/writers/chromeos_adml_writer.py b/components/policy/tools/template_writers/writers/chromeos_adml_writer.py
deleted file mode 100755
index 24b30e8..0000000
--- a/components/policy/tools/template_writers/writers/chromeos_adml_writer.py
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2017 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import base64
-
-from writers import adml_writer
-from writers.admx_writer import AdmxElementType
-
-
-def GetWriter(config):
-  '''Factory method for creating ADMLWriter objects for the Chrome OS platform.
-  See the constructor of TemplateWriter for description of arguments.
-  '''
-  return ChromeOSADMLWriter(['chrome_os'], config)
-
-
-class ChromeOSADMLWriter(adml_writer.ADMLWriter):
-  ''' Class for generating Chrome OS ADML policy templates. It is used by the
-  PolicyTemplateGenerator to write the ADML file.
-  '''
-
-  # Overridden.
-  # These ADML files are used to generate GPO for Active Directory managed
-  # Chrome OS devices.
-  def IsPolicySupported(self, policy):
-    return self.IsCrOSManagementSupported(policy, 'active_directory') and \
-           super(ChromeOSADMLWriter, self).IsPolicySupported(policy)
-
-  # Overridden.
-  def _GetAdmxElementType(self, policy):
-    return AdmxElementType.GetType(policy, allow_multi_strings=True)
diff --git a/components/policy/tools/template_writers/writers/chromeos_adml_writer_unittest.py b/components/policy/tools/template_writers/writers/chromeos_adml_writer_unittest.py
deleted file mode 100755
index dd7dc3d..0000000
--- a/components/policy/tools/template_writers/writers/chromeos_adml_writer_unittest.py
+++ /dev/null
@@ -1,109 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2017 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-"""Unittests for writers.chromeos_adml_writer."""
-
-import os
-import sys
-import unittest
-if __name__ == '__main__':
-  sys.path.append(os.path.join(os.path.dirname(__file__), '../../../..'))
-
-from writers import chromeos_adml_writer
-from writers import adml_writer_unittest
-from writers.admx_writer import AdmxElementType
-
-
-class ChromeOsAdmlWriterUnittest(adml_writer_unittest.AdmlWriterUnittest):
-
-  # Overridden.
-  def _GetWriter(self, config):
-    return chromeos_adml_writer.GetWriter(config)
-
-  # Overridden
-  def GetCategory(self):
-    return "cros_test_category"
-
-  # Overridden
-  def GetCategoryString(self):
-    return "CrOSTestCategory"
-
-  # Overridden.
-  def testPlatform(self):
-    # Test that the writer correctly chooses policies of platform Chrome OS.
-    self.assertTrue(
-        self.writer.IsPolicySupported({
-            'supported_on': [{
-                'platform': 'chrome_os'
-            }, {
-                'platform': 'aaa'
-            }]
-        }))
-    self.assertFalse(
-        self.writer.IsPolicySupported({
-            'supported_on': [{
-                'platform': 'win'
-            }, {
-                'platform': 'aaa'
-            }]
-        }))
-
-  def testOnlySupportsAdPolicies(self):
-    # Tests whether only Active Directory managed policies are supported (Google
-    # cloud only managed polices are not put in the ADMX file).
-    policy = {
-        'name':
-        'PolicyName',
-        'supported_on': [{
-            'product': 'chrome_os',
-            'platform': 'chrome_os',
-            'since_version': '8',
-            'until_version': '',
-        }],
-    }
-    self.assertTrue(self.writer.IsPolicySupported(policy))
-
-    policy['supported_chrome_os_management'] = ['google_cloud']
-    self.assertFalse(self.writer.IsPolicySupported(policy))
-
-    policy['supported_chrome_os_management'] = ['active_directory']
-    self.assertTrue(self.writer.IsPolicySupported(policy))
-
-  # Overridden.
-  def testDictionaryPolicy(self, is_external=False):
-    dict_policy = {
-        'name': 'DictionaryPolicyStub',
-        'type': 'external' if is_external else 'dict',
-        'caption': 'Dictionary policy caption',
-        'label': 'Dictionary policy label',
-        'desc': 'This is a test description.',
-    }
-    self._InitWriterForAddingPolicies(self.writer, dict_policy)
-    self.writer.WritePolicy(dict_policy)
-    # Assert generated string elements.
-    output = self.GetXMLOfChildren(self.writer._string_table_elem)
-    expected_output = (
-        '<string id="DictionaryPolicyStub">Dictionary policy caption</string>\n'
-        '<string id="DictionaryPolicyStub_Explain">'
-        'This is a test description.\n'
-        'See https://cloud.google.com/docs/chrome-enterprise/policies/?policy='
-        'DictionaryPolicyStub\n</string>\n'
-        '<string id="DictionaryPolicyStub_Legacy">'
-        'Dictionary policy label (deprecated)</string>')
-    self.AssertXMLEquals(output, expected_output)
-    # Assert generated presentation elements.
-    output = self.GetXMLOfChildren(self.writer._presentation_table_elem)
-    expected_output = (
-        '<presentation id="DictionaryPolicyStub">\n'
-        '  <textBox refId="DictionaryPolicyStub_Legacy">\n'
-        '    <label>Dictionary policy label (deprecated)</label>\n'
-        '  </textBox>\n'
-        '  <multiTextBox defaultHeight="8" refId="DictionaryPolicyStub">'
-        'Dictionary policy label</multiTextBox>\n'
-        '</presentation>')
-    self.AssertXMLEquals(output, expected_output)
-
-
-if __name__ == '__main__':
-  unittest.main()
diff --git a/components/policy/tools/template_writers/writers/chromeos_admx_writer.py b/components/policy/tools/template_writers/writers/chromeos_admx_writer.py
deleted file mode 100755
index 9a3da91..0000000
--- a/components/policy/tools/template_writers/writers/chromeos_admx_writer.py
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2017 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import base64
-
-from writers import admx_writer
-from writers.admx_writer import AdmxElementType
-
-
-def GetWriter(config):
-  '''Factory method for creating ADMXWriter objects for the Chrome OS platform
-  See the constructor of TemplateWriter for description of arguments.
-  '''
-  return ChromeOSADMXWriter(['chrome_os'], config)
-
-
-class ChromeOSADMXWriter(admx_writer.ADMXWriter):
-  '''Class for generating Chrome OS policy templates in the ADMX format.
-  It is used by PolicyTemplateGenerator to write ADMX files.
-  '''
-
-  # Overridden.
-  def GetClass(self, policy):
-    is_device_only = 'device_only' in policy and policy['device_only']
-    return 'Machine' if is_device_only else 'User'
-
-  # Overridden.
-  # These ADMX templates are used to generate GPO for Active Directory managed
-  # Chrome OS devices.
-  def IsPolicySupported(self, policy):
-    return self.IsCrOSManagementSupported(policy, 'active_directory') and \
-           super(ChromeOSADMXWriter, self).IsPolicySupported(policy)
-
-  # Overridden.
-  def _GetAdmxElementType(self, policy):
-    return AdmxElementType.GetType(policy, allow_multi_strings=True)
diff --git a/components/policy/tools/template_writers/writers/chromeos_admx_writer_unittest.py b/components/policy/tools/template_writers/writers/chromeos_admx_writer_unittest.py
deleted file mode 100755
index 884e35e..0000000
--- a/components/policy/tools/template_writers/writers/chromeos_admx_writer_unittest.py
+++ /dev/null
@@ -1,151 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2017 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-"""Unittests for writers.chromeos_admx_writer."""
-
-import os
-import sys
-import unittest
-if __name__ == '__main__':
-  sys.path.append(os.path.join(os.path.dirname(__file__), '../../../..'))
-
-from writers import chromeos_admx_writer
-from writers import admx_writer_unittest
-from writers.admx_writer import AdmxElementType
-
-
-class ChromeOsAdmxWriterUnittest(admx_writer_unittest.AdmxWriterUnittest):
-
-  # Overridden.
-  def _GetWriter(self, config):
-    return chromeos_admx_writer.GetWriter(config)
-
-  # Overridden.
-  def _GetKey(self):
-    return "CrOSTest"
-
-  # Overridden.
-  def _GetCategory(self):
-    return "cros_test_category"
-
-  # Overridden.
-  def _GetCategoryRec(self):
-    return "cros_test_recommended_category"
-
-  # Overridden.
-  def _GetNamespace(self):
-    return "ADMXWriter.Test.Namespace.ChromeOS"
-
-  # Overridden.
-  def testPlatform(self):
-    # Test that the writer correctly chooses policies of platform Chrome OS.
-    self.assertTrue(
-        self.writer.IsPolicySupported({
-            'supported_on': [{
-                'platform': 'chrome_os'
-            }, {
-                'platform': 'aaa'
-            }]
-        }))
-    self.assertFalse(
-        self.writer.IsPolicySupported({
-            'supported_on': [{
-                'platform': 'win'
-            }, {
-                'platform': 'aaa'
-            }]
-        }))
-
-  def testUserPolicy(self):
-    self.doTestUserOrDevicePolicy(False)
-
-  def testDevicePolicy(self):
-    self.doTestUserOrDevicePolicy(True)
-
-  def doTestUserOrDevicePolicy(self, is_device_only):
-    # Tests whether CLASS attribute is 'User' for user policies and 'Machine'
-    # for device policies.
-    main_policy = {
-        'name': 'DummyMainPolicy',
-        'type': 'main',
-        'device_only': is_device_only,
-    }
-
-    expected_class = 'Machine' if is_device_only else 'User'
-
-    self._initWriterForPolicy(self.writer, main_policy)
-    self.writer.WritePolicy(main_policy)
-
-    output = self.GetXMLOfChildren(self._GetPoliciesElement(self.writer._doc))
-    expected_output = ('<policy class="' + expected_class + '"'
-                       ' displayName="$(string.DummyMainPolicy)"'
-                       ' explainText="$(string.DummyMainPolicy_Explain)"'
-                       ' key="Software\\Policies\\' + self._GetKey() + '"'
-                       ' name="DummyMainPolicy"'
-                       ' presentation="$(presentation.DummyMainPolicy)"'
-                       ' valueName="DummyMainPolicy">\n'
-                       '  <parentCategory ref="PolicyGroup"/>\n'
-                       '  <supportedOn ref="SUPPORTED_TESTOS"/>\n'
-                       '  <enabledValue>\n'
-                       '    <decimal value="1"/>\n'
-                       '  </enabledValue>\n'
-                       '  <disabledValue>\n'
-                       '    <decimal value="0"/>\n'
-                       '  </disabledValue>\n'
-                       '</policy>')
-
-    self.AssertXMLEquals(output, expected_output)
-
-  def testOnlySupportsAdPolicies(self):
-    # Tests whether only Active Directory managed policies are supported (Google
-    # cloud only managed polices are not put in the ADMX file).
-    policy = {
-        'name':
-        'PolicyName',
-        'supported_on': [{
-            'product': 'chrome_os',
-            'platform': 'chrome_os',
-            'since_version': '8',
-            'until_version': '',
-        }],
-    }
-    self.assertTrue(self.writer.IsPolicySupported(policy))
-
-    policy['supported_chrome_os_management'] = ['google_cloud']
-    self.assertFalse(self.writer.IsPolicySupported(policy))
-
-    policy['supported_chrome_os_management'] = ['active_directory']
-    self.assertTrue(self.writer.IsPolicySupported(policy))
-
-  #Overridden
-  def testDictionaryPolicy(self, is_external=False):
-    dict_policy = {
-        'name': 'SampleDictionaryPolicy',
-        'type': 'external' if is_external else 'dict',
-    }
-    self._initWriterForPolicy(self.writer, dict_policy)
-
-    self.writer.WritePolicy(dict_policy)
-    output = self.GetXMLOfChildren(self._GetPoliciesElement(self.writer._doc))
-    expected_output = (
-        '<policy class="' + self.writer.GetClass(dict_policy) + '"'
-        ' displayName="$(string.SampleDictionaryPolicy)"'
-        ' explainText="$(string.SampleDictionaryPolicy_Explain)"'
-        ' key="Software\\Policies\\' + self._GetKey() + '"'
-        ' name="SampleDictionaryPolicy"'
-        ' presentation="$(presentation.SampleDictionaryPolicy)">\n'
-        '  <parentCategory ref="PolicyGroup"/>\n'
-        '  <supportedOn ref="SUPPORTED_TESTOS"/>\n'
-        '  <elements>\n'
-        '    <text id="SampleDictionaryPolicy_Legacy" maxLength="1000000"'
-        ' valueName="SampleDictionaryPolicy"/>\n'
-        '    <multiText id="SampleDictionaryPolicy" maxLength="1000000"'
-        ' valueName="SampleDictionaryPolicy"/>\n'
-        '  </elements>\n'
-        '</policy>')
-    self.AssertXMLEquals(output, expected_output)
-
-
-if __name__ == '__main__':
-  unittest.main()
diff --git a/components/policy/tools/template_writers/writers/doc_writer.py b/components/policy/tools/template_writers/writers/doc_writer.py
index 2f969193..d7622f9 100755
--- a/components/policy/tools/template_writers/writers/doc_writer.py
+++ b/components/policy/tools/template_writers/writers/doc_writer.py
@@ -262,9 +262,6 @@
     examples = self._AddStyledElement(parent, 'dl', ['dd dl'])
     if self.IsPolicySupportedOnWindows(policy):
       self._AddListExampleWindowsChromeOS(examples, policy, True)
-    if self.IsPolicyOrItemSupportedOnPlatform(
-        policy, 'chrome_os', management='active_directory'):
-      self._AddListExampleWindowsChromeOS(examples, policy, False)
     if (self.IsPolicyOrItemSupportedOnPlatform(policy, 'android') or
         self.IsPolicyOrItemSupportedOnPlatform(policy, 'linux')):
       self._AddListExampleAndroidLinux(examples, policy)
@@ -393,9 +390,6 @@
     examples = self._AddStyledElement(parent, 'dl', ['dd dl'])
     if self.IsPolicySupportedOnWindows(policy):
       self._AddDictionaryExampleWindowsChromeOS(examples, policy, True)
-    if self.IsPolicyOrItemSupportedOnPlatform(
-        policy, 'chrome_os', management='active_directory'):
-      self._AddDictionaryExampleWindowsChromeOS(examples, policy, False)
     if (self.IsPolicyOrItemSupportedOnPlatform(policy, 'android') or
         self.IsPolicyOrItemSupportedOnPlatform(policy, 'linux')):
       self._AddDictionaryExampleAndroidLinux(examples, policy)
@@ -461,9 +455,7 @@
     policy_type = policy['type']
     if policy_type == 'main':
       pieces = []
-      if self.IsPolicySupportedOnWindows(policy) or \
-         self.IsPolicyOrItemSupportedOnPlatform(policy, 'chrome_os',
-                                          management='active_directory'):
+      if self.IsPolicySupportedOnWindows(policy):
         value = '0x00000001' if example_value else '0x00000000'
         pieces.append(value + ' (Windows)')
       if self.IsPolicyOrItemSupportedOnPlatform(policy, 'linux'):
@@ -480,9 +472,7 @@
       self.AddText(parent, '"%s"' % example_value)
     elif policy_type in ('int', 'int-enum'):
       pieces = []
-      if self.IsPolicySupportedOnWindows(policy) or \
-         self.IsPolicyOrItemSupportedOnPlatform(policy, 'chrome_os',
-                                          management='active_directory'):
+      if self.IsPolicySupportedOnWindows(policy):
         pieces.append('0x%08x (Windows)' % example_value)
       if self.IsPolicyOrItemSupportedOnPlatform(policy, 'linux'):
         pieces.append('%d (Linux)' % example_value)
@@ -594,10 +584,8 @@
           'Android:%s' % self._RESTRICTION_TYPE_MAP[policy['type']])
       if policy['type'] in ('dict', 'external', 'list'):
         is_complex_policy = True
-    if ((self.IsPolicySupportedOnWindows(policy) or
-         self.IsPolicyOrItemSupportedOnPlatform(
-             policy, 'chrome_os', management='active_directory')) and
-        self._REG_TYPE_MAP.get(policy['type'], None)):
+    if ((self.IsPolicySupportedOnWindows(policy))
+        and self._REG_TYPE_MAP.get(policy['type'], None)):
       qualified_types.append('Windows:%s' % self._REG_TYPE_MAP[policy['type']])
       if policy['type'] in ('dict', 'external'):
         is_complex_policy = True
@@ -615,11 +603,6 @@
       self._AddPolicyAttribute(dl, 'oma_uri', self._GetOmaUriPath(policy),
                                ['.monospace'])
 
-    if self.IsPolicyOrItemSupportedOnPlatform(
-        policy, 'chrome_os', management='active_directory'):
-      key_name = self._GetRegistryKeyName(policy, False)
-      self._AddPolicyAttribute(dl, 'chrome_os_reg_loc',
-                               key_name + '\\' + policy['name'], ['.monospace'])
     if (self.IsPolicyOrItemSupportedOnPlatform(policy, 'linux') or
         self.IsPolicyOrItemSupportedOnPlatform(policy, 'mac')):
       self._AddPolicyAttribute(dl, 'mac_linux_pref_name', policy['name'],
@@ -656,12 +639,10 @@
     if 'url_schema' in policy:
       dd = self._AddPolicyAttribute(dl, 'url_schema')
       self._AddTextWithLinks(dd, policy['url_schema'])
-    if (self.IsPolicySupportedOnWindows(policy) or
-        self.IsPolicyOrItemSupportedOnPlatform(policy, 'linux') or
-        self.IsPolicyOrItemSupportedOnPlatform(policy, 'android') or
-        self.IsPolicyOrItemSupportedOnPlatform(policy, 'mac') or
-        self.IsPolicyOrItemSupportedOnPlatform(
-            policy, 'chrome_os', management='active_directory')):
+    if (self.IsPolicySupportedOnWindows(policy)
+        or self.IsPolicyOrItemSupportedOnPlatform(policy, 'linux')
+        or self.IsPolicyOrItemSupportedOnPlatform(policy, 'android')
+        or self.IsPolicyOrItemSupportedOnPlatform(policy, 'mac')):
       # Don't add an example for Google cloud managed ChromeOS policies.
       dd = self._AddPolicyAttribute(dl, 'example_value')
       self._AddExample(dd, policy)
diff --git a/components/policy/tools/template_writers/writers/doc_writer_unittest.py b/components/policy/tools/template_writers/writers/doc_writer_unittest.py
index eb65d795..17ca1a27 100755
--- a/components/policy/tools/template_writers/writers/doc_writer_unittest.py
+++ b/components/policy/tools/template_writers/writers/doc_writer_unittest.py
@@ -81,9 +81,6 @@
         'doc_win_example_value': {
             'text': '_test_example_value_win'
         },
-        'doc_chrome_os_example_value': {
-            'text': '_test_example_value_chrome_os'
-        },
         'doc_feature_dynamic_refresh': {
             'text': '_test_feature_dynamic_refresh'
         },
@@ -135,9 +132,6 @@
         'doc_oma_uri': {
             'text': '_test_oma_uri'
         },
-        'doc_chrome_os_reg_loc': {
-            'text': '_test_chrome_os_reg_loc'
-        },
         'doc_bla': {
             'text': '_test_bla'
         },
@@ -382,11 +376,6 @@
         'MockKey\\PolicyName\\1 = &quot;Foo&quot;\n'
         'MockKey\\PolicyName\\2 = &quot;Bar&quot;'
         '</dd>'
-        '<dt>_test_example_value_chrome_os</dt>'
-        '<dd style="style_.monospace;style_.pre-wrap;">'
-        'MockKeyCrOS\\PolicyName\\1 = &quot;Foo&quot;\n'
-        'MockKeyCrOS\\PolicyName\\2 = &quot;Bar&quot;'
-        '</dd>'
         '<dt>Android/Linux:</dt>'
         '<dd style="style_.monospace;style_.pre-wrap;">'
         '[\n'
@@ -655,8 +644,6 @@
         '<dd style="style_.monospace;">MockKey\TestPolicyName</dd>'
         '<dt style="style_dt;">_test_oma_uri</dt>'
         '<dd style="style_.monospace;">.\\Device\\Vendor\\MSFT\\Policy\\Config\\Chrome~Policy~chromium\\TestPolicyName</dd>'
-        '<dt style="style_dt;">_test_chrome_os_reg_loc</dt>'
-        '<dd style="style_.monospace;">MockKeyCrOS\TestPolicyName</dd>'
         '<dt style="style_dt;">_test_mac_linux_pref_name</dt>'
         '<dd style="style_.monospace;">TestPolicyName</dd>'
         '<dt style="style_dt;">_test_android_restriction_name</dt>'
@@ -794,8 +781,6 @@
         '<dd style="style_.monospace;">MockKey\TestPolicyName</dd>'
         '<dt style="style_dt;">_test_oma_uri</dt>'
         '<dd style="style_.monospace;">.\\Device\\Vendor\\MSFT\\Policy\\Config\\Chrome~Policy~chromium\\TestPolicyName</dd>'
-        '<dt style="style_dt;">_test_chrome_os_reg_loc</dt>'
-        '<dd style="style_.monospace;">MockKeyCrOS\TestPolicyName</dd>'
         '<dt style="style_dt;">_test_mac_linux_pref_name</dt>'
         '<dd style="style_.monospace;">TestPolicyName</dd>'
         '<dt style="style_dt;">_test_supported_on</dt>'
@@ -830,12 +815,6 @@
         '  &quot;foo&quot;: 123\n'
         '}'
         '</dd>'
-        '<dt>_test_example_value_chrome_os</dt>'
-        '<dd style="style_.monospace;style_.pre-wrap;">'
-        'MockKeyCrOS\TestPolicyName = {\n'
-        '  &quot;foo&quot;: 123\n'
-        '}'
-        '</dd>'
         '<dt>Android/Linux:</dt>'
         '<dd style="style_.monospace;style_.pre-wrap;">'
         'TestPolicyName: {\n'
@@ -1032,8 +1011,6 @@
         '<dd style="style_.monospace;">MockKeyRec\TestPolicyName</dd>'
         '<dt style="style_dt;">_test_oma_uri</dt>'
         '<dd style="style_.monospace;">.\\Device\\Vendor\\MSFT\\Policy\\Config\\Chrome~Policy~chromium\\TestPolicyName</dd>'
-        '<dt style="style_dt;">_test_chrome_os_reg_loc</dt>'
-        '<dd style="style_.monospace;">MockKeyCrOSRec\TestPolicyName</dd>'
         '<dt style="style_dt;">_test_mac_linux_pref_name</dt>'
         '<dd style="style_.monospace;">TestPolicyName</dd>'
         '<dt style="style_dt;">_test_android_restriction_name</dt>'
@@ -1140,8 +1117,6 @@
         '<dd style="style_.monospace;">MockKey\\PolicyName</dd>'
         '<dt style="style_dt;">_test_oma_uri</dt>'
         '<dd style="style_.monospace;">.\\Device\\Vendor\\MSFT\\Policy\\Config\\Chrome~Policy~chromium\\PolicyName</dd>'
-        '<dt style="style_dt;">_test_chrome_os_reg_loc</dt>'
-        '<dd style="style_.monospace;">MockKeyCrOS\\PolicyName</dd>'
         '<dt style="style_dt;">_test_mac_linux_pref_name</dt>'
         '<dd style="style_.monospace;">PolicyName</dd>'
         '<dt style="style_dt;">_test_supported_on</dt>'
@@ -1229,8 +1204,6 @@
         '<dd style="style_.monospace;">MockKey\\PolicyName</dd>'
         '<dt style="style_dt;">_test_oma_uri</dt>'
         '<dd style="style_.monospace;">.\\Device\\Vendor\\MSFT\\Policy\\Config\\Chrome~Policy~chromium\\PolicyName</dd>'
-        '<dt style="style_dt;">_test_chrome_os_reg_loc</dt>'
-        '<dd style="style_.monospace;">MockKeyCrOS\\PolicyName</dd>'
         '<dt style="style_dt;">_test_mac_linux_pref_name</dt>'
         '<dd style="style_.monospace;">PolicyName</dd>'
         '<dt style="style_dt;">_test_supported_on</dt>'
@@ -1731,105 +1704,6 @@
         self.doc_root.toxml(),
         '<root><p>Paragraph 1</p><p>Paragraph 2</p><p>Paragraph 3</p></root>')
 
-  def testGoogleCloudChromeOsPolicies(self):
-    # Tests whether ChromeOS policies with management type 'google_cloud'
-    # don't print example values etc. since they are managed through Google's
-    # Admin console, not Active Directory GPO.
-    policy = {
-        'name':
-        'PolicyName',
-        'caption':
-        'PolicyCaption',
-        'desc':
-        'PolicyDesc',
-        'type':
-        'int',
-        'features': {},
-        'example_value':
-        42,
-        'supported_on': [{
-            'product': 'chrome_os',
-            'platform': 'chrome_os',
-            'since_version': '8',
-            'until_version': '',
-        }],
-        'supported_chrome_os_management': ['google_cloud']
-    }
-    self.writer._AddPolicySection(self.doc_root, policy)
-    self.assertEquals(
-        self.doc_root.toxml(), '<root>'
-        '<div style="margin-left: 0px">'
-        '<h3><a name="PolicyName"/>PolicyName</h3>'
-        '<span>PolicyCaption</span>'
-        '<dl>'
-        '<dt style="style_dt;">_test_data_type</dt>'
-        '<dd>Integer</dd>'
-        '<dt style="style_dt;">_test_supported_on</dt>'
-        '<dd>'
-        '<ul style="style_ul;">'
-        '<li>ChromeOS (ChromeOS) ..8..</li>'
-        '</ul>'
-        '</dd>'
-        '<dt style="style_dt;">_test_supported_features</dt>'
-        '<dd></dd>'
-        '<dt style="style_dt;">_test_description</dt>'
-        '<dd><p>PolicyDesc</p></dd>'
-        '</dl>'
-        '<a href="#top">_test_back_to_top</a>'
-        '</div>'
-        '</root>')
-
-  def testActiveDirectoryChromeOsPolicies(self):
-    # Tests whether ChromeOS policies with management type 'active_directory'
-    # print example values etc.
-    policy = {
-        'name':
-        'PolicyName',
-        'caption':
-        'PolicyCaption',
-        'desc':
-        'PolicyDesc',
-        'type':
-        'int',
-        'features': {},
-        'example_value':
-        42,
-        'supported_on': [{
-            'product': 'chrome_os',
-            'platform': 'chrome_os',
-            'since_version': '8',
-            'until_version': '',
-        }],
-        'supported_chrome_os_management': ['active_directory']
-    }
-    self.writer._AddPolicySection(self.doc_root, policy)
-    self.assertEquals(
-        self.doc_root.toxml(), '<root>'
-        '<div style="margin-left: 0px">'
-        '<h3><a name="PolicyName"/>PolicyName</h3>'
-        '<span>PolicyCaption</span>'
-        '<dl>'
-        '<dt style="style_dt;">_test_data_type</dt>'
-        '<dd>Integer [Windows:REG_DWORD]</dd>'
-        '<dt style="style_dt;">_test_chrome_os_reg_loc</dt>'
-        '<dd style="style_.monospace;">MockKeyCrOS\\PolicyName</dd>'
-        '<dt style="style_dt;">_test_supported_on</dt>'
-        '<dd>'
-        '<ul style="style_ul;">'
-        '<li>ChromeOS (ChromeOS) ..8..</li>'
-        '</ul>'
-        '</dd>'
-        '<dt style="style_dt;">_test_supported_features</dt>'
-        '<dd></dd>'
-        '<dt style="style_dt;">_test_description</dt>'
-        '<dd><p>PolicyDesc</p></dd>'
-        '<dt style="style_dt;">_test_example_value</dt>'
-        '<dd>0x0000002a (Windows)</dd>'
-        '</dl>'
-        '<a href="#top">_test_back_to_top</a>'
-        '</div>'
-        '</root>')
-
 
 if __name__ == '__main__':
   unittest.main()
diff --git a/components/policy/tools/template_writers/writers/template_writer.py b/components/policy/tools/template_writers/writers/template_writer.py
index f78dab0..534c96ee 100755
--- a/components/policy/tools/template_writers/writers/template_writer.py
+++ b/components/policy/tools/template_writers/writers/template_writer.py
@@ -130,11 +130,7 @@
     '''Checks if the given policy is internal only'''
     return self.GetPolicyFeature(policy, 'internal_only', False)
 
-  def IsPolicyOrItemSupportedOnPlatform(self,
-                                        item,
-                                        platform,
-                                        product=None,
-                                        management=None):
+  def IsPolicyOrItemSupportedOnPlatform(self, item, platform, product=None):
     '''Checks if |item| is supported on |product| for |platform|. If
     |product| is not specified, only the platform support is checked.
     If |management| is specified, also checks for support for Chrome OS
@@ -146,12 +142,7 @@
         'win', 'mac', 'linux', 'chrome_os', 'android'.
       product: Optional product to check; one of
         'chrome', 'chrome_frame', 'chrome_os', 'webview'.
-      management: Optional Chrome OS management type to check; one of
-        'active_directory', 'google_cloud'.
     '''
-    if management and not self.IsCrOSManagementSupported(item, management):
-      return False
-
     for supported_on in item['supported_on']:
       if (platform == supported_on['platform']
           and (not product or product in supported_on['product'])
@@ -179,19 +170,6 @@
     return (self.IsPolicyOrItemSupportedOnPlatform(policy, 'win', product)
             or self.IsPolicyOrItemSupportedOnPlatform(policy, 'win7', product))
 
-  def IsCrOSManagementSupported(self, policy, management):
-    '''Checks whether |policy| supports the Chrome OS |management| type.
-
-    Args:
-      policy: The dictionary of the policy.
-      management: Chrome OS management type to check; one of
-        'active_directory', 'google_cloud'.
-    '''
-    # By default, i.e. if supported_chrome_os_management is not set, all
-    # management types are supported.
-    return management in policy.get('supported_chrome_os_management',
-                                    ['active_directory', 'google_cloud'])
-
   def IsVersionSupported(self, policy, supported_on):
     '''Checks whether the policy is supported on current version'''
     major_version = self._GetChromiumMajorVersion()
diff --git a/components/privacy_sandbox/masked_domain_list/masked_domain_list.proto b/components/privacy_sandbox/masked_domain_list/masked_domain_list.proto
index d58b49e..90ae1583 100644
--- a/components/privacy_sandbox/masked_domain_list/masked_domain_list.proto
+++ b/components/privacy_sandbox/masked_domain_list/masked_domain_list.proto
@@ -15,6 +15,12 @@
 
   optional string domain = 1;
   repeated Experiment experiments = 3 [packed = true];
+
+  // If true, clients not part of an experiment group will ignore this Resource.
+  optional bool exclude_default_group = 4;
+
+  // Non-zero IDs of experiment groups that include this Resource.
+  repeated int64 experiment_group_ids = 5;
 }
 
 // Contains ownership information about resources that are used in a 3rd party
diff --git a/components/safe_browsing/core/browser/db/v4_local_database_manager.cc b/components/safe_browsing/core/browser/db/v4_local_database_manager.cc
index f13b28b..4d7839b 100644
--- a/components/safe_browsing/core/browser/db/v4_local_database_manager.cc
+++ b/components/safe_browsing/core/browser/db/v4_local_database_manager.cc
@@ -421,7 +421,7 @@
 }
 
 bool V4LocalDatabaseManager::ChecksAreAlwaysAsync() const {
-  return false;
+  return GetPrefixMatchesIsAsync();
 }
 
 bool V4LocalDatabaseManager::CheckBrowseUrl(
diff --git a/components/segmentation_platform/internal/selection/request_dispatcher.cc b/components/segmentation_platform/internal/selection/request_dispatcher.cc
index 69f2d63..fe6ce6c 100644
--- a/components/segmentation_platform/internal/selection/request_dispatcher.cc
+++ b/components/segmentation_platform/internal/selection/request_dispatcher.cc
@@ -70,7 +70,7 @@
     for (const auto& config : storage_service_->config_holder()->configs()) {
       request_handlers_[config->segmentation_key] = RequestHandler::Create(
           *config, std::move(result_providers[config->segmentation_key]),
-          execution_service);
+          execution_service, storage_service_);
     }
   }
 
@@ -165,40 +165,29 @@
                        RawResult(PredictionStatus::kFailed)));
     return;
   }
+
   Config* config =
       storage_service_->config_holder()->GetConfigForSegmentationKey(
           segmentation_key);
   CHECK(config);
 
-  if (!options.on_demand_execution) {
-    // Returns result directly from prefs for non-ondemand models.
-    auto pred_result = storage_service_->cached_result_provider()
-                           ->GetPredictionResultForClient(segmentation_key);
-    RawResult raw_result(PredictionStatus::kFailed);
-    if (pred_result) {
-      raw_result = PostProcessor().GetRawResult(*pred_result,
-                                                PredictionStatus::kSucceeded);
-
-      storage_service_->cached_result_writer()->MarkResultAsUsed(config);
-      stats::RecordSegmentSelectionFailure(
-          *config, stats::SegmentationSelectionFailureReason::
-                       kClassificationResultFromPrefs);
-    } else {
-      stats::RecordSegmentSelectionFailure(
-          *config, stats::SegmentationSelectionFailureReason::
-                       kClassificationResultNotAvailableInPrefs);
-    }
-
-    base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
-        FROM_HERE,
-        base::BindOnce(std::move(callback), /*is_cached_result=*/true,
-                       std::move(raw_result)));
+  if (options.on_demand_execution) {
+    ExecuteOnDemand(segmentation_key, config, options, input_context,
+                    std::move(callback));
     return;
   }
+  HandleCachedExecution(segmentation_key, config, options, input_context,
+                        std::move(callback));
+}
 
-  // TODO(ssid): Support cached results for all APIs.
-  DCHECK(options.on_demand_execution);
-
+void RequestDispatcher::ExecuteOnDemand(
+    const std::string& segmentation_key,
+    const Config* config,
+    const PredictionOptions& options,
+    scoped_refptr<InputContext> input_context,
+    WrappedCallback callback) {
+  DCHECK(options.on_demand_execution ||
+         (!options.on_demand_execution && options.fallback_allowed));
   // For on-demand results, we need to run the models for which we need DB
   // initialization to be complete. Hence cache the request if platform
   // initialization isn't completed yet.
@@ -228,11 +217,87 @@
   auto iter = request_handlers_.find(segmentation_key);
   CHECK(iter != request_handlers_.end());
   auto final_callback =
-      base::BindOnce(std::move(callback), /*is_cached_result=*/false);
+      base::BindOnce(&RequestDispatcher::OnFinishedOnDemandExecution,
+                     weak_ptr_factory_.GetWeakPtr(), segmentation_key, config,
+                     options, input_context, std::move(callback));
   iter->second->GetPredictionResult(options, input_context,
                                     std::move(final_callback));
 }
 
+void RequestDispatcher::OnFinishedOnDemandExecution(
+    const std::string& segmentation_key,
+    const Config* config,
+    const PredictionOptions& options,
+    scoped_refptr<InputContext> input_context,
+    WrappedCallback callback,
+    const RawResult& raw_result) {
+  if (raw_result.status == PredictionStatus::kFailed) {
+    // If there is no result from ondemand execution and fallback is enabled
+    // return cached result if previously result was cached.
+    if (options.on_demand_execution && options.fallback_allowed &&
+        options.can_update_cache_for_future_requests) {
+      HandleCachedExecution(segmentation_key, config, options, input_context,
+                            std::move(callback));
+      return;
+    }
+    stats::RecordSegmentSelectionFailure(
+        *config, stats::SegmentationSelectionFailureReason::
+                     kOnDemandModelExecutionFailed);
+  }
+  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), /*is_cached_result=*/false,
+                                std::move(raw_result)));
+}
+
+void RequestDispatcher::HandleCachedExecution(
+    const std::string& segmentation_key,
+    const Config* config,
+    const PredictionOptions& options,
+    scoped_refptr<InputContext> input_context,
+    WrappedCallback callback) {
+  // Returns result directly from prefs for non-ondemand models.
+  auto pred_result =
+      storage_service_->cached_result_provider()->GetPredictionResultForClient(
+          segmentation_key);
+
+  RawResult raw_result(PredictionStatus::kFailed);
+  bool cached_execution_fallback_on_failure =
+      !options.on_demand_execution && options.fallback_allowed;
+
+  if (!pred_result && cached_execution_fallback_on_failure) {
+    // Execute ondemand if no cached result is available and fallback is
+    // allowed. Only supported for cached execution.
+    stats::RecordSegmentSelectionFailure(
+        *config, stats::SegmentationSelectionFailureReason::
+                     kCachedResultUnavailableExecutingOndemand);
+    ExecuteOnDemand(segmentation_key, config, options, input_context,
+                    std::move(callback));
+    return;
+  }
+
+  if (pred_result) {
+    // Return cached result.
+    raw_result = PostProcessor().GetRawResult(*pred_result,
+                                              PredictionStatus::kSucceeded);
+
+    storage_service_->cached_result_writer()->MarkResultAsUsed(config);
+    stats::RecordSegmentSelectionFailure(
+        *config, stats::SegmentationSelectionFailureReason::
+                     kClassificationResultFromPrefs);
+  } else {
+    // Return failure if no cached result is available.
+    // This happens in two scenarios:
+    // 1. Ondemand execution fails and fallback execution also fails.
+    // 2. Cached execution fails and fallback is not allowed.
+    stats::RecordSegmentSelectionFailure(
+        *config, stats::SegmentationSelectionFailureReason::
+                     kClassificationResultNotAvailableInPrefs);
+  }
+  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), /*is_cached_result=*/true,
+                                std::move(raw_result)));
+}
+
 void RequestDispatcher::GetClassificationResult(
     const std::string& segmentation_key,
     const PredictionOptions& options,
diff --git a/components/segmentation_platform/internal/selection/request_dispatcher.h b/components/segmentation_platform/internal/selection/request_dispatcher.h
index 4c22d713..f36b71b3 100644
--- a/components/segmentation_platform/internal/selection/request_dispatcher.h
+++ b/components/segmentation_platform/internal/selection/request_dispatcher.h
@@ -77,6 +77,25 @@
                       scoped_refptr<InputContext> input_context,
                       WrappedCallback callback);
 
+  void ExecuteOnDemand(const std::string& segmentation_key,
+                       const Config* config,
+                       const PredictionOptions& options,
+                       scoped_refptr<InputContext> input_context,
+                       WrappedCallback callback);
+
+  void OnFinishedOnDemandExecution(const std::string& segmentation_key,
+                                   const Config* config,
+                                   const PredictionOptions& options,
+                                   scoped_refptr<InputContext> input_context,
+                                   WrappedCallback callback,
+                                   const RawResult& raw_result);
+
+  void HandleCachedExecution(const std::string& segmentation_key,
+                             const Config* config,
+                             const PredictionOptions& options,
+                             scoped_refptr<InputContext> input_context,
+                             WrappedCallback callback);
+
   // Wrap the result callback for recording metrics and converting raw result to
   // necessary result type.
   template <typename ResultType>
diff --git a/components/segmentation_platform/internal/selection/request_dispatcher_unittest.cc b/components/segmentation_platform/internal/selection/request_dispatcher_unittest.cc
index 5eb236e0..31ded2ed 100644
--- a/components/segmentation_platform/internal/selection/request_dispatcher_unittest.cc
+++ b/components/segmentation_platform/internal/selection/request_dispatcher_unittest.cc
@@ -22,6 +22,7 @@
 #include "components/segmentation_platform/internal/database/signal_database.h"
 #include "components/segmentation_platform/internal/database/signal_storage_config.h"
 #include "components/segmentation_platform/internal/database/storage_service.h"
+#include "components/segmentation_platform/internal/metadata/metadata_utils.h"
 #include "components/segmentation_platform/internal/metadata/metadata_writer.h"
 #include "components/segmentation_platform/internal/mock_ukm_data_manager.h"
 #include "components/segmentation_platform/internal/post_processor/post_processing_test_utils.h"
@@ -101,6 +102,10 @@
         kAdaptiveToolbarClient,
         SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_ADAPTIVE_TOOLBAR));
     configs.back()->auto_execute_and_cache = false;
+    configs.emplace_back(test_utils::CreateTestConfig(
+        kShoppingUserSegmentationKey,
+        SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_SHOPPING_USER));
+    configs.back()->auto_execute_and_cache = true;
     auto config_holder = std::make_unique<ConfigHolder>(std::move(configs));
 
     prefs_.registry()->RegisterStringPref(kSegmentationClientResultPrefs,
@@ -108,7 +113,6 @@
     client_result_prefs_ = std::make_unique<ClientResultPrefs>(&prefs_);
     auto cached_result_writer = std::make_unique<CachedResultWriter>(
         client_result_prefs_.get(), &clock_);
-    cached_result_writer_ = cached_result_writer.get();
     storage_service_ = std::make_unique<StorageService>(
         nullptr, nullptr, nullptr, nullptr, std::move(config_holder),
         &ukm_data_manager_);
@@ -127,6 +131,10 @@
     request_handler2_ = handler2.get();
     request_dispatcher_->set_request_handler_for_testing(kAdaptiveToolbarClient,
                                                          std::move(handler2));
+    auto handler3 = std::make_unique<MockRequestHandler>();
+    request_handler3_ = handler3.get();
+    request_dispatcher_->set_request_handler_for_testing(
+        kShoppingUserSegmentationKey, std::move(handler3));
   }
 
   void OnGetClassificationResult(base::RepeatingClosure closure,
@@ -155,7 +163,7 @@
   std::unique_ptr<StorageService> storage_service_;
   raw_ptr<MockRequestHandler, DanglingUntriaged> request_handler1_ = nullptr;
   raw_ptr<MockRequestHandler, DanglingUntriaged> request_handler2_ = nullptr;
-  raw_ptr<CachedResultWriter> cached_result_writer_;
+  raw_ptr<MockRequestHandler, DanglingUntriaged> request_handler3_ = nullptr;
   std::unique_ptr<RequestDispatcher> request_dispatcher_;
 };
 
@@ -424,5 +432,135 @@
   EXPECT_EQ(0, request_dispatcher_->GetPendingActionCountForTesting());
 }
 
+TEST_F(RequestDispatcherTest, TestOnDemandWithFallback) {
+  // Result available in client prefs.
+  client_result_prefs_->SaveClientResultToPrefs(
+      kDeviceSwitcherKey,
+      metadata_utils::CreateClientResultFromPredResult(
+          CreatePredictionResultWithBinaryClassifier(kTestLabel1),
+          /*timestamp=*/base::Time::Now()));
+  auto cached_result_provider = std::make_unique<CachedResultProvider>(
+      client_result_prefs_.get(), storage_service_->config_holder()->configs());
+  storage_service_->set_cached_result_provider_for_testing(
+      std::move(cached_result_provider));
+
+  base::RunLoop loop;
+  PredictionOptions options = PredictionOptions::ForOnDemand(true);
+  options.can_update_cache_for_future_requests = true;
+
+  // Init platform.
+  std::map<std::string, std::unique_ptr<SegmentResultProvider>>
+      result_providers;
+  ExecutionService execution_service;
+  // Set platform as initialized.
+  request_dispatcher_->OnPlatformInitialized(true, &execution_service,
+                                             std::move(result_providers));
+  // Set both models as initialized, now requests should be dispatched
+  // immediately without queueing.
+  request_dispatcher_->OnModelUpdated(
+      SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_DEVICE_SWITCHER);
+
+  // Request from client.
+  RawResult raw_result(PredictionStatus::kFailed);
+  EXPECT_CALL(*request_handler1_, GetPredictionResult(_, _, _))
+      .WillOnce(Invoke([&raw_result](const PredictionOptions& options,
+                                     scoped_refptr<InputContext> input_context,
+                                     RawResultCallback callback) {
+        std::move(callback).Run(raw_result);
+      }));
+
+  ClassificationResult result(PredictionStatus::kSucceeded);
+  result.ordered_labels.emplace_back(kTestLabel1);
+  request_dispatcher_->GetClassificationResult(
+      kDeviceSwitcherClient, options, scoped_refptr<InputContext>(),
+      base::BindOnce(&RequestDispatcherTest::OnGetClassificationResult,
+                     base::Unretained(this), loop.QuitClosure(), result));
+  loop.Run();
+  EXPECT_EQ(0, request_dispatcher_->GetPendingActionCountForTesting());
+}
+
+TEST_F(RequestDispatcherTest, TestCachedExecutionWithoutFallback) {
+  // Result available in client prefs.
+  client_result_prefs_->SaveClientResultToPrefs(
+      kShoppingUserSegmentationKey,
+      metadata_utils::CreateClientResultFromPredResult(
+          CreatePredictionResultWithBinaryClassifier(kTestLabel1),
+          /*timestamp=*/base::Time::Now()));
+  auto cached_result_provider = std::make_unique<CachedResultProvider>(
+      client_result_prefs_.get(), storage_service_->config_holder()->configs());
+  storage_service_->set_cached_result_provider_for_testing(
+      std::move(cached_result_provider));
+
+  base::RunLoop loop;
+  PredictionOptions options = PredictionOptions::ForCached(true);
+  options.can_update_cache_for_future_requests = true;
+
+  // Init platform.
+  std::map<std::string, std::unique_ptr<SegmentResultProvider>>
+      result_providers;
+  ExecutionService execution_service;
+  // Set platform as initialized.
+  request_dispatcher_->OnPlatformInitialized(true, &execution_service,
+                                             std::move(result_providers));
+  // Set both models as initialized, now requests should be dispatched
+  // immediately without queueing.
+  request_dispatcher_->OnModelUpdated(
+      SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_SHOPPING_USER);
+
+  // Request from client.
+  ClassificationResult result(PredictionStatus::kSucceeded);
+  result.ordered_labels.emplace_back(kTestLabel1);
+  request_dispatcher_->GetClassificationResult(
+      kShoppingUserSegmentationKey, options, scoped_refptr<InputContext>(),
+      base::BindOnce(&RequestDispatcherTest::OnGetClassificationResult,
+                     base::Unretained(this), loop.QuitClosure(), result));
+  loop.Run();
+  EXPECT_EQ(0, request_dispatcher_->GetPendingActionCountForTesting());
+}
+
+TEST_F(RequestDispatcherTest, TestCachedExecutionWithFallback) {
+  // Result not available in client prefs.
+  auto cached_result_provider = std::make_unique<CachedResultProvider>(
+      client_result_prefs_.get(), storage_service_->config_holder()->configs());
+  storage_service_->set_cached_result_provider_for_testing(
+      std::move(cached_result_provider));
+
+  base::RunLoop loop;
+  PredictionOptions options = PredictionOptions::ForCached(true);
+  options.can_update_cache_for_future_requests = true;
+
+  // Init platform.
+  std::map<std::string, std::unique_ptr<SegmentResultProvider>>
+      result_providers;
+  ExecutionService execution_service;
+  // Set platform as initialized.
+  request_dispatcher_->OnPlatformInitialized(true, &execution_service,
+                                             std::move(result_providers));
+  // Set both models as initialized, now requests should be dispatched
+  // immediately without queueing.
+  request_dispatcher_->OnModelUpdated(
+      SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_SHOPPING_USER);
+
+  // Request from client.
+  RawResult raw_result(PredictionStatus::kSucceeded);
+  raw_result.result = CreatePredictionResultWithBinaryClassifier(kTestLabel1);
+  EXPECT_CALL(*request_handler3_, GetPredictionResult(_, _, _))
+      .WillRepeatedly(
+          Invoke([&raw_result](const PredictionOptions& options,
+                               scoped_refptr<InputContext> input_context,
+                               RawResultCallback callback) {
+            std::move(callback).Run(raw_result);
+          }));
+
+  ClassificationResult result(PredictionStatus::kSucceeded);
+  result.ordered_labels.emplace_back(kTestLabel1);
+  request_dispatcher_->GetClassificationResult(
+      kShoppingUserSegmentationKey, options, scoped_refptr<InputContext>(),
+      base::BindOnce(&RequestDispatcherTest::OnGetClassificationResult,
+                     base::Unretained(this), loop.QuitClosure(), result));
+  loop.Run();
+  EXPECT_EQ(0, request_dispatcher_->GetPendingActionCountForTesting());
+}
+
 }  // namespace
 }  // namespace segmentation_platform
diff --git a/components/segmentation_platform/internal/selection/request_handler.cc b/components/segmentation_platform/internal/selection/request_handler.cc
index dcd834f..866b4d2b 100644
--- a/components/segmentation_platform/internal/selection/request_handler.cc
+++ b/components/segmentation_platform/internal/selection/request_handler.cc
@@ -24,7 +24,8 @@
  public:
   RequestHandlerImpl(const Config& config,
                      std::unique_ptr<SegmentResultProvider> result_provider,
-                     ExecutionService* execution_service);
+                     ExecutionService* execution_service,
+                     StorageService* storage_service);
   ~RequestHandlerImpl() override;
 
   // Disallow copy/assign.
@@ -42,6 +43,7 @@
                       SegmentResultProvider::SegmentResultCallback callback);
 
   void OnGetPredictionResult(
+      const PredictionOptions& options,
       scoped_refptr<InputContext> input_context,
       RawResultCallback callback,
       std::unique_ptr<SegmentResultProvider::SegmentResult> result);
@@ -60,16 +62,20 @@
   // Pointer to the execution service.
   const raw_ptr<ExecutionService> execution_service_ = nullptr;
 
+  const raw_ptr<StorageService> storage_service_ = nullptr;
+
   base::WeakPtrFactory<RequestHandlerImpl> weak_ptr_factory_{this};
 };
 
 RequestHandlerImpl::RequestHandlerImpl(
     const Config& config,
     std::unique_ptr<SegmentResultProvider> result_provider,
-    ExecutionService* execution_service)
+    ExecutionService* execution_service,
+    StorageService* storage_service)
     : config_(config),
       result_provider_(std::move(result_provider)),
-      execution_service_(execution_service) {}
+      execution_service_(execution_service),
+      storage_service_(storage_service) {}
 
 RequestHandlerImpl::~RequestHandlerImpl() = default;
 
@@ -77,11 +83,12 @@
     const PredictionOptions& options,
     scoped_refptr<InputContext> input_context,
     RawResultCallback callback) {
-  DCHECK(options.on_demand_execution);
+  DCHECK(options.on_demand_execution ||
+         (!options.on_demand_execution && options.fallback_allowed));
   GetModelResult(options, input_context,
                  base::BindOnce(&RequestHandlerImpl::OnGetPredictionResult,
-                                weak_ptr_factory_.GetWeakPtr(), input_context,
-                                std::move(callback)));
+                                weak_ptr_factory_.GetWeakPtr(), options,
+                                input_context, std::move(callback)));
 }
 
 void RequestHandlerImpl::GetModelResult(
@@ -94,7 +101,7 @@
 
   // Note that, this assumes that a client has only one model.
   result_options->segment_id = config_->segments.begin()->first;
-  result_options->ignore_db_scores = options.on_demand_execution;
+  result_options->ignore_db_scores = true;
   result_options->input_context = input_context;
   result_options->callback = std::move(callback);
 
@@ -102,6 +109,7 @@
 }
 
 void RequestHandlerImpl::OnGetPredictionResult(
+    const PredictionOptions& options,
     scoped_refptr<InputContext> input_context,
     RawResultCallback callback,
     std::unique_ptr<SegmentResultProvider::SegmentResult> segment_result) {
@@ -121,13 +129,16 @@
     stats::RecordSegmentSelectionFailure(
         *config_, stats::GetSuccessOrFailureReason(segment_result->state));
     stats::RecordClassificationResultComputed(*config_, segment_result->result);
-  } else {
-    stats::RecordSegmentSelectionFailure(
-        *config_, stats::SegmentationSelectionFailureReason::
-                      kOnDemandModelExecutionFailed);
+    // Update prefs for future requests.
+    if (options.can_update_cache_for_future_requests) {
+      proto::ClientResult client_result =
+          metadata_utils::CreateClientResultFromPredResult(
+              segment_result->result, base::Time::Now());
+      storage_service_->cached_result_writer()->UpdatePrefsIfExpired(
+          &(*config_), client_result, PlatformOptions::CreateDefault());
+    }
   }
-  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), std::move(result)));
+  std::move(callback).Run(std::move(result));
 }
 
 TrainingRequestId RequestHandlerImpl::CollectTrainingData(
@@ -149,9 +160,10 @@
 std::unique_ptr<RequestHandler> RequestHandler::Create(
     const Config& config,
     std::unique_ptr<SegmentResultProvider> result_provider,
-    ExecutionService* execution_service) {
+    ExecutionService* execution_service,
+    StorageService* storage_service) {
   return std::make_unique<RequestHandlerImpl>(
-      config, std::move(result_provider), execution_service);
+      config, std::move(result_provider), execution_service, storage_service);
 }
 
 }  // namespace segmentation_platform
diff --git a/components/segmentation_platform/internal/selection/request_handler.h b/components/segmentation_platform/internal/selection/request_handler.h
index 030da1f..83c4f2b 100644
--- a/components/segmentation_platform/internal/selection/request_handler.h
+++ b/components/segmentation_platform/internal/selection/request_handler.h
@@ -31,7 +31,8 @@
   static std::unique_ptr<RequestHandler> Create(
       const Config& config,
       std::unique_ptr<SegmentResultProvider> result_provider,
-      ExecutionService* execution_service);
+      ExecutionService* execution_service,
+      StorageService* storage_service);
 
   // Fetches raw result for on demand executions.
   virtual void GetPredictionResult(const PredictionOptions& options,
diff --git a/components/segmentation_platform/internal/selection/request_handler_unittest.cc b/components/segmentation_platform/internal/selection/request_handler_unittest.cc
index 0d2331e..97f1b32 100644
--- a/components/segmentation_platform/internal/selection/request_handler_unittest.cc
+++ b/components/segmentation_platform/internal/selection/request_handler_unittest.cc
@@ -8,9 +8,17 @@
 #include "base/metrics/user_metrics.h"
 #include "base/run_loop.h"
 #include "base/test/gmock_callback_support.h"
+#include "base/test/simple_test_clock.h"
 #include "base/test/task_environment.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/segmentation_platform/internal/constants.h"
 #include "components/segmentation_platform/internal/data_collection/training_data_collector.h"
+#include "components/segmentation_platform/internal/database/signal_database.h"
+#include "components/segmentation_platform/internal/database/signal_storage_config.h"
+#include "components/segmentation_platform/internal/database/storage_service.h"
 #include "components/segmentation_platform/internal/metadata/metadata_writer.h"
+#include "components/segmentation_platform/internal/mock_ukm_data_manager.h"
 #include "components/segmentation_platform/internal/post_processor/post_processing_test_utils.h"
 #include "components/segmentation_platform/internal/selection/segment_result_provider.h"
 #include "components/segmentation_platform/public/config.h"
@@ -34,6 +42,7 @@
 // Test Ids.
 const proto::SegmentId kSegmentId =
     proto::SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB;
+const std::string& kTestClientKey = "test_client";
 
 class MockResultProvider : public SegmentResultProvider {
  public:
@@ -97,11 +106,30 @@
     training_data_collector_ = training_data_collector.get();
     execution_service_.set_training_data_collector_for_testing(
         std::move(training_data_collector));
-    config_ = test_utils::CreateTestConfig("test_client", kSegmentId);
+    config_ = test_utils::CreateTestConfig(kTestClientKey, kSegmentId);
     auto provider = std::make_unique<MockResultProvider>();
     result_provider_ = provider.get();
-    request_handler_ = RequestHandler::Create(*config_, std::move(provider),
-                                              &execution_service_);
+
+    std::vector<std::unique_ptr<Config>> configs;
+    configs.emplace_back(
+        test_utils::CreateTestConfig(kTestClientKey, kSegmentId));
+    configs.back()->auto_execute_and_cache = false;
+    auto config_holder = std::make_unique<ConfigHolder>(std::move(configs));
+
+    prefs_.registry()->RegisterStringPref(kSegmentationClientResultPrefs,
+                                          std::string());
+    client_result_prefs_ = std::make_unique<ClientResultPrefs>(&prefs_);
+    auto cached_result_writer = std::make_unique<CachedResultWriter>(
+        client_result_prefs_.get(), &clock_);
+    cached_result_writer_ = cached_result_writer.get();
+    storage_service_ = std::make_unique<StorageService>(
+        nullptr, nullptr, nullptr, nullptr, std::move(config_holder),
+        &ukm_data_manager_);
+    storage_service_->set_cached_result_writer_for_testing(
+        std::move(cached_result_writer));
+    request_handler_ =
+        RequestHandler::Create(*(config_.get()), std::move(provider),
+                               &execution_service_, storage_service_.get());
   }
 
   void OnGetPredictionResult(base::RepeatingClosure closure,
@@ -115,8 +143,14 @@
   base::test::TaskEnvironment task_environment_{
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
   std::unique_ptr<Config> config_;
+  base::SimpleTestClock clock_;
+  TestingPrefServiceSimple prefs_;
+  std::unique_ptr<ClientResultPrefs> client_result_prefs_;
   ExecutionService execution_service_;
   raw_ptr<MockTrainingDataCollector> training_data_collector_;
+  MockUkmDataManager ukm_data_manager_;
+  std::unique_ptr<StorageService> storage_service_;
+  raw_ptr<CachedResultWriter> cached_result_writer_;
   std::unique_ptr<RequestHandler> request_handler_;
   raw_ptr<MockResultProvider> result_provider_ = nullptr;
 };
@@ -124,6 +158,7 @@
 TEST_F(RequestHandlerTest, GetPredictionResult) {
   PredictionOptions options;
   options.on_demand_execution = true;
+  options.can_update_cache_for_future_requests = true;
 
   EXPECT_CALL(
       *training_data_collector_,
@@ -147,7 +182,46 @@
           }));
 
   base::RunLoop loop;
-  RawResult result(PredictionStatus::kFailed);
+  request_handler_->GetPredictionResult(
+      options, scoped_refptr<InputContext>(),
+      base::BindOnce(&RequestHandlerTest::OnGetPredictionResult,
+                     base::Unretained(this), loop.QuitClosure()));
+  loop.Run();
+
+  // Check prefs is updated if `can_update_cache_for_future_requests` is set to
+  // true.
+  const proto::ClientResult* result_from_pref =
+      client_result_prefs_->ReadClientResultFromPrefs(
+          config_->segmentation_key);
+  EXPECT_EQ(CreatePredictionResultWithBinaryClassifier().SerializeAsString(),
+            result_from_pref->client_result().SerializeAsString());
+}
+
+TEST_F(RequestHandlerTest, ExecuteOndemandAsFallbackCase) {
+  PredictionOptions options;
+  options.on_demand_execution = false;
+  options.fallback_allowed = true;
+
+  EXPECT_CALL(
+      *training_data_collector_,
+      OnDecisionTime(
+          kSegmentId, _, proto::TrainingOutputs::TriggerConfig::ONDEMAND,
+          absl::make_optional(ModelProvider::Request{1, 2, 3}), false))
+      .WillOnce(Return(TrainingRequestId::FromUnsafeValue(15)));
+  EXPECT_CALL(*result_provider_, GetSegmentResult(_))
+      .WillOnce(Invoke([](std::unique_ptr<
+                           SegmentResultProvider::GetResultOptions> options) {
+        EXPECT_TRUE(options->ignore_db_scores);
+        EXPECT_EQ(options->segment_id, kSegmentId);
+        auto result = std::make_unique<SegmentResultProvider::SegmentResult>(
+            SegmentResultProvider::ResultState::kServerModelExecutionScoreUsed,
+            CreatePredictionResultWithBinaryClassifier(),
+            /*rank=*/2);
+        result->model_inputs = {1, 2, 3};
+        std::move(options->callback).Run(std::move(result));
+      }));
+
+  base::RunLoop loop;
   request_handler_->GetPredictionResult(
       options, scoped_refptr<InputContext>(),
       base::BindOnce(&RequestHandlerTest::OnGetPredictionResult,
@@ -158,6 +232,7 @@
 TEST_F(RequestHandlerTest, GetGenericPredictionResult) {
   PredictionOptions options;
   options.on_demand_execution = true;
+  options.can_update_cache_for_future_requests = false;
 
   EXPECT_CALL(
       *training_data_collector_,
@@ -181,7 +256,6 @@
           }));
 
   base::RunLoop loop;
-  RawResult result(PredictionStatus::kFailed);
   request_handler_->GetPredictionResult(
       options, scoped_refptr<InputContext>(),
       base::BindOnce(&RequestHandlerTest::OnGetPredictionResult,
diff --git a/components/segmentation_platform/internal/selection/segment_result_provider.cc b/components/segmentation_platform/internal/selection/segment_result_provider.cc
index b8fef16..bc59ee5 100644
--- a/components/segmentation_platform/internal/selection/segment_result_provider.cc
+++ b/components/segmentation_platform/internal/selection/segment_result_provider.cc
@@ -365,8 +365,8 @@
                              : ResultState::kServerModelExecutionFailed;
     segment_result = std::make_unique<SegmentResult>(state);
     VLOG(1) << __func__ << ": " << (is_default_model ? "Default" : "Server")
-            << " model execution failed"
-            << " for segment " << proto::SegmentId_Name(segment_id);
+            << " model execution failed" << " for segment "
+            << proto::SegmentId_Name(segment_id);
   }
 
   if (request_state->options->save_results_to_db) {
diff --git a/components/segmentation_platform/internal/stats.h b/components/segmentation_platform/internal/stats.h
index b63f6c40..8c1b396 100644
--- a/components/segmentation_platform/internal/stats.h
+++ b/components/segmentation_platform/internal/stats.h
@@ -242,7 +242,9 @@
   kClassificationResultNotAvailableInPrefs = 26,
   kDefaultModelDatabaseScoreUsed = 27,
   kDefaultModelDatabaseScoreNotReady = 28,
-  kMaxValue = kDefaultModelDatabaseScoreNotReady,
+  kCachedResultUnavailableExecutingOndemand = 29,
+  kOnDemandExecutionFailedReturningCachedResult = 30,
+  kMaxValue = kOnDemandExecutionFailedReturningCachedResult,
 };
 
 // Records the reason for failure or success to compute a segment selection.
diff --git a/components/segmentation_platform/public/BUILD.gn b/components/segmentation_platform/public/BUILD.gn
index 83dffe91..5fccdd9 100644
--- a/components/segmentation_platform/public/BUILD.gn
+++ b/components/segmentation_platform/public/BUILD.gn
@@ -26,6 +26,7 @@
     "local_state_helper.h",
     "model_provider.cc",
     "model_provider.h",
+    "prediction_options.cc",
     "prediction_options.h",
     "result.cc",
     "result.h",
diff --git a/components/segmentation_platform/public/prediction_options.cc b/components/segmentation_platform/public/prediction_options.cc
new file mode 100644
index 0000000..6240e94a
--- /dev/null
+++ b/components/segmentation_platform/public/prediction_options.cc
@@ -0,0 +1,33 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/segmentation_platform/public/prediction_options.h"
+
+#include "base/values.h"
+
+namespace segmentation_platform {
+
+PredictionOptions::PredictionOptions(bool on_demand_execution,
+                                     bool can_update_cache_for_future_requests,
+                                     bool fallback_allowed)
+    : can_update_cache_for_future_requests(
+          can_update_cache_for_future_requests),
+      on_demand_execution(on_demand_execution),
+      fallback_allowed(fallback_allowed) {}
+
+// static
+PredictionOptions PredictionOptions::ForCached(bool can_fallback_to_execution) {
+  return PredictionOptions(/*on_demand_execution=*/false,
+                           /*can_update_cache_for_future_requests=*/true,
+                           can_fallback_to_execution);
+}
+
+// static
+PredictionOptions PredictionOptions::ForOnDemand(bool can_fallback_to_cache) {
+  return PredictionOptions(/*on_demand_execution=*/true,
+                           /*can_update_cache_for_future_requests=*/false,
+                           can_fallback_to_cache);
+}
+
+}  // namespace segmentation_platform
diff --git a/components/segmentation_platform/public/prediction_options.h b/components/segmentation_platform/public/prediction_options.h
index baa10acd..23bc47f 100644
--- a/components/segmentation_platform/public/prediction_options.h
+++ b/components/segmentation_platform/public/prediction_options.h
@@ -10,13 +10,39 @@
 // Options that can be specified when invoking SegmentationPlatformService APIs.
 struct PredictionOptions {
   PredictionOptions() = default;
+  explicit PredictionOptions(bool on_demand_execution,
+                             bool cached_execution_fallback_on_failure = false,
+                             bool fallback_allowed = false);
   ~PredictionOptions() = default;
 
   PredictionOptions(const PredictionOptions&) = default;
   PredictionOptions& operator=(const PredictionOptions&) = default;
 
+  // Cannot pass input_context. Set this option to get cached results.
+  // If `can_fallback_to_execution` is set to true, then if cached results are
+  // not available, the service will try executing the model.
+  // `can_update_cache_for_future_requests` is default set to true which
+  // means cached results will be updated, if model is executed successfully.
+  static PredictionOptions ForCached(bool can_fallback_to_execution = false);
+
+  // Set this option to get results by executing model ondemand.
+  // If `can_fallback_to_execution` is set to true, then if there are no results
+  // available from executing model ondemand, the service will try returning
+  // cached results.
+  static PredictionOptions ForOnDemand(bool can_fallback_to_cache = false);
+
+  // Set to true if the execution results can be reused for future API calls to
+  // fetch cached results.
+  bool can_update_cache_for_future_requests{false};
+
   // Set to true if on demand execution is to be done.
-  bool on_demand_execution = false;
+  bool on_demand_execution{false};
+
+  // Set to true if executing the fallback case if allowed in case
+  // Example : If `can_fallback_to_cache = true` for ondemand option, returning
+  // result using fallback is allowed. If `can_fallback_to_execution = true` for
+  // cached option, returning result using fallback is allowed.
+  bool fallback_allowed{false};
 };
 
 }  // namespace segmentation_platform
diff --git a/components/signin/core/browser/cookie_settings_util.cc b/components/signin/core/browser/cookie_settings_util.cc
index 4bb076d..525f4b84 100644
--- a/components/signin/core/browser/cookie_settings_util.cc
+++ b/components/signin/core/browser/cookie_settings_util.cc
@@ -6,6 +6,7 @@
 
 #include "components/content_settings/core/browser/cookie_settings.h"
 #include "google_apis/gaia/gaia_urls.h"
+#include "net/cookies/cookie_constants.h"
 #include "net/cookies/cookie_setting_override.h"
 #include "net/cookies/site_for_cookies.h"
 #include "url/gurl.h"
@@ -37,9 +38,11 @@
 
   return !cookie_settings ||
          cookie_settings->ShouldDeleteCookieOnExit(
-             settings, "." + gaia_url.host(), true) ||
+             settings, "." + gaia_url.host(),
+             net::CookieSourceScheme::kSecure) ||
          cookie_settings->ShouldDeleteCookieOnExit(
-             settings, "." + google_url.host(), true);
+             settings, "." + google_url.host(),
+             net::CookieSourceScheme::kSecure);
 }
 
 }  // namespace signin
diff --git a/components/sync/engine/loopback_server/loopback_server.cc b/components/sync/engine/loopback_server/loopback_server.cc
index 58c80af0..2551a85 100644
--- a/components/sync/engine/loopback_server/loopback_server.cc
+++ b/components/sync/engine/loopback_server/loopback_server.cc
@@ -244,8 +244,7 @@
 }
 
 LoopbackServer::~LoopbackServer() {
-  if (writer_.HasPendingWrite())
-    writer_.DoScheduledWrite();
+  FlushToDisk();
 }
 
 void LoopbackServer::Init() {
@@ -394,6 +393,12 @@
   keystore_keys_.push_back(GenerateNewKeystoreKey());
 }
 
+void LoopbackServer::FlushToDisk() {
+  if (writer_.HasPendingWrite()) {
+    writer_.DoScheduledWrite();
+  }
+}
+
 bool LoopbackServer::HandleGetUpdatesRequest(
     const sync_pb::GetUpdatesMessage& get_updates,
     const std::string& store_birthday,
diff --git a/components/sync/engine/loopback_server/loopback_server.h b/components/sync/engine/loopback_server/loopback_server.h
index 6949b26..9d455cb7 100644
--- a/components/sync/engine/loopback_server/loopback_server.h
+++ b/components/sync/engine/loopback_server/loopback_server.h
@@ -99,6 +99,8 @@
       base::RepeatingCallback<sync_pb::CommitResponse::ResponseType(
           const LoopbackServerEntity& entity)>;
 
+  void FlushToDisk();
+
   // ImportantFileWriter::DataSerializer:
   absl::optional<std::string> SerializeData() override;
 
diff --git a/components/sync/test/fake_server.cc b/components/sync/test/fake_server.cc
index 7c3658d..feea500 100644
--- a/components/sync/test/fake_server.cc
+++ b/components/sync/test/fake_server.cc
@@ -345,6 +345,10 @@
   loopback_server_->OverrideResponseType(std::move(response_type_override));
 }
 
+void FakeServer::FlushToDisk() {
+  loopback_server_->FlushToDisk();
+}
+
 base::Value::Dict FakeServer::GetEntitiesAsDictForTesting() {
   DCHECK(thread_checker_.CalledOnValidThread());
   return loopback_server_->GetEntitiesAsDictForTesting();
diff --git a/components/sync/test/fake_server.h b/components/sync/test/fake_server.h
index f78a809c..2ad9a29a 100644
--- a/components/sync/test/fake_server.h
+++ b/components/sync/test/fake_server.h
@@ -268,6 +268,11 @@
   void OverrideResponseType(
       syncer::LoopbackServer::ResponseTypeProvider response_type_override);
 
+  // Performs any pending disk write immediately. This is useful on platforms
+  // where shutdown isn't graceful, and this object may not be destructed
+  // properly (otherwise, the destructor takes care of this automatically).
+  void FlushToDisk();
+
  private:
   // Analogous to HandleCommand() but deals with parsed protos.
   net::HttpStatusCode HandleParsedCommand(
diff --git a/components/sync_preferences/common_syncable_prefs_database.cc b/components/sync_preferences/common_syncable_prefs_database.cc
index 1e3cca1..8c22de70 100644
--- a/components/sync_preferences/common_syncable_prefs_database.cc
+++ b/components/sync_preferences/common_syncable_prefs_database.cc
@@ -120,211 +120,211 @@
 
 const auto& SyncablePreferences() {
   // List of syncable preferences common across platforms.
-  static const auto kCommonSyncablePrefsAllowlist = base::MakeFixedFlatMap<
-      base::StringPiece, SyncablePrefMetadata>({
-    {autofill::prefs::kAutofillCreditCardEnabled,
-     {syncable_prefs_ids::kAutofillCreditCardEnabled, syncer::PREFERENCES,
-      PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {autofill::prefs::kAutofillHasSeenIban,
-         {syncable_prefs_ids::kAutofillHasSeenIban, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {autofill::prefs::kAutofillLastVersionDeduped,
-         {syncable_prefs_ids::kAutofillLastVersionDeduped, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {autofill::prefs::kAutofillProfileEnabled,
-         {syncable_prefs_ids::kAutofillProfileEnabled, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {bookmarks::prefs::kShowAppsShortcutInBookmarkBar,
-         {syncable_prefs_ids::kShowAppsShortcutInBookmarkBar,
-          syncer::PREFERENCES, PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {bookmarks::prefs::kShowBookmarkBar,
-         {syncable_prefs_ids::kShowBookmarkBar, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {bookmarks::prefs::kShowManagedBookmarksInBookmarkBar,
-         {syncable_prefs_ids::kShowManagedBookmarksInBookmarkBar,
-          syncer::PREFERENCES, PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {browsing_data::prefs::kClearBrowsingDataHistoryNoticeShownTimes,
-         {syncable_prefs_ids::kClearBrowsingDataHistoryNoticeShownTimes,
-          syncer::PREFERENCES, PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {browsing_data::prefs::kDeleteBrowsingHistory,
-         {syncable_prefs_ids::kDeleteBrowsingHistory, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {browsing_data::prefs::kDeleteBrowsingHistoryBasic,
-         {syncable_prefs_ids::kDeleteBrowsingHistoryBasic, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {browsing_data::prefs::kDeleteCache,
-         {syncable_prefs_ids::kDeleteCache, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {browsing_data::prefs::kDeleteCacheBasic,
-         {syncable_prefs_ids::kDeleteCacheBasic, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {browsing_data::prefs::kDeleteCookies,
-         {syncable_prefs_ids::kDeleteCookies, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {browsing_data::prefs::kDeleteCookiesBasic,
-         {syncable_prefs_ids::kDeleteCookiesBasic, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {browsing_data::prefs::kDeleteDownloadHistory,
-         {syncable_prefs_ids::kDeleteDownloadHistory, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {browsing_data::prefs::kDeleteFormData,
-         {syncable_prefs_ids::kDeleteFormData, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {browsing_data::prefs::kDeleteHostedAppsData,
-         {syncable_prefs_ids::kDeleteHostedAppsData, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {browsing_data::prefs::kDeletePasswords,
-         {syncable_prefs_ids::kDeletePasswords, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {browsing_data::prefs::kDeleteSiteSettings,
-         {syncable_prefs_ids::kDeleteSiteSettings, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {browsing_data::prefs::kDeleteTimePeriod,
-         {syncable_prefs_ids::kDeleteTimePeriod, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {browsing_data::prefs::kDeleteTimePeriodBasic,
-         {syncable_prefs_ids::kDeleteTimePeriodBasic, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {browsing_data::prefs::kDeleteTimePeriodV2,
-         {syncable_prefs_ids::kDeleteTimePeriodV2, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {browsing_data::prefs::kDeleteTimePeriodV2Basic,
-         {syncable_prefs_ids::kDeleteTimePeriodV2Basic, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {browsing_data::prefs::kLastClearBrowsingDataTime,
-         {syncable_prefs_ids::kLastClearBrowsingDataTime, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {browsing_data::prefs::kPreferencesMigratedToBasic,
-         {syncable_prefs_ids::kPreferencesMigratedToBasic, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {commerce::kPriceEmailNotificationsEnabled,
-         {syncable_prefs_ids::kPriceEmailNotificationsEnabled,
-          syncer::PREFERENCES, PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {dom_distiller::prefs::kFont,
-         {syncable_prefs_ids::kFont, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {dom_distiller::prefs::kOfferReaderMode,
-         {syncable_prefs_ids::kOfferReaderMode, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {dom_distiller::prefs::kReaderForAccessibility,
-         {syncable_prefs_ids::kReaderForAccessibility, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {dom_distiller::prefs::kTheme,
-         {syncable_prefs_ids::kTheme, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {language::prefs::kAcceptLanguages,
-         {syncable_prefs_ids::kAcceptLanguages, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {language::prefs::kSelectedLanguages,
-         {syncable_prefs_ids::kSelectedLanguages, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {metrics::kSyncDemographicsPrefName,
-         {syncable_prefs_ids::kSyncDemographicsPrefName,
-          syncer::PRIORITY_PREFERENCES, PrefSensitivity::kNone,
-          MergeBehavior::kNone}},
-        {ntp_tiles::prefs::kCustomLinksInitialized,
-         {syncable_prefs_ids::kCustomLinksInitialized, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {ntp_tiles::prefs::kCustomLinksList,
-         {syncable_prefs_ids::kCustomLinksList, syncer::PREFERENCES,
-          PrefSensitivity::kSensitiveRequiresHistory, MergeBehavior::kNone}},
-        {omnibox::kKeywordSpaceTriggeringEnabled,
-         {syncable_prefs_ids::kKeywordSpaceTriggeringEnabled,
-          syncer::PREFERENCES, PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {password_manager::prefs::kCredentialsEnableAutosignin,
-         {syncable_prefs_ids::kCredentialsEnableAutosignin,
-          syncer::PRIORITY_PREFERENCES, PrefSensitivity::kNone,
-          MergeBehavior::kNone}},
-        {password_manager::prefs::kCredentialsEnableService,
-         {syncable_prefs_ids::kCredentialsEnableService,
-          syncer::PRIORITY_PREFERENCES, PrefSensitivity::kNone,
-          MergeBehavior::kNone}},
-        {password_manager::prefs::kPasswordDismissCompromisedAlertEnabled,
-         {syncable_prefs_ids::kPasswordDismissCompromisedAlertEnabled,
-          syncer::PREFERENCES, PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {password_manager::prefs::kPasswordLeakDetectionEnabled,
-         {syncable_prefs_ids::kPasswordLeakDetectionEnabled,
-          syncer::PREFERENCES, PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {password_manager::prefs::kSyncedLastTimePasswordCheckCompleted,
-         {syncable_prefs_ids::kSyncedLastTimePasswordCheckCompleted,
-          syncer::PRIORITY_PREFERENCES, PrefSensitivity::kNone,
-          MergeBehavior::kNone}},
-        {password_manager::prefs::kWasAutoSignInFirstRunExperienceShown,
-         {syncable_prefs_ids::kWasAutoSignInFirstRunExperienceShown,
-          syncer::PRIORITY_PREFERENCES, PrefSensitivity::kNone,
-          MergeBehavior::kNone}},
-        {payments::kCanMakePaymentEnabled,
-         {syncable_prefs_ids::kCanMakePaymentEnabled, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {prefs::kAccountTailoredSecurityUpdateTimestamp,
-         {syncable_prefs_ids::kAccountTailoredSecurityUpdateTimestamp,
-          syncer::PRIORITY_PREFERENCES, PrefSensitivity::kNone,
-          MergeBehavior::kNone}},
-        {prefs::kCookieControlsMode,
-         {syncable_prefs_ids::kCookieControlsMode, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {prefs::kSafeBrowsingEnabled,
-         {syncable_prefs_ids::kSafeBrowsingEnabled, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
+  static const auto kCommonSyncablePrefsAllowlist =
+      base::MakeFixedFlatMap<base::StringPiece, SyncablePrefMetadata>({
+          {autofill::prefs::kAutofillCreditCardEnabled,
+           {syncable_prefs_ids::kAutofillCreditCardEnabled, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {autofill::prefs::kAutofillHasSeenIban,
+           {syncable_prefs_ids::kAutofillHasSeenIban, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {autofill::prefs::kAutofillLastVersionDeduped,
+           {syncable_prefs_ids::kAutofillLastVersionDeduped,
+            syncer::PREFERENCES, PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {autofill::prefs::kAutofillProfileEnabled,
+           {syncable_prefs_ids::kAutofillProfileEnabled, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {bookmarks::prefs::kShowAppsShortcutInBookmarkBar,
+           {syncable_prefs_ids::kShowAppsShortcutInBookmarkBar,
+            syncer::PREFERENCES, PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {bookmarks::prefs::kShowBookmarkBar,
+           {syncable_prefs_ids::kShowBookmarkBar, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {bookmarks::prefs::kShowManagedBookmarksInBookmarkBar,
+           {syncable_prefs_ids::kShowManagedBookmarksInBookmarkBar,
+            syncer::PREFERENCES, PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {browsing_data::prefs::kClearBrowsingDataHistoryNoticeShownTimes,
+           {syncable_prefs_ids::kClearBrowsingDataHistoryNoticeShownTimes,
+            syncer::PREFERENCES, PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {browsing_data::prefs::kDeleteBrowsingHistory,
+           {syncable_prefs_ids::kDeleteBrowsingHistory, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {browsing_data::prefs::kDeleteBrowsingHistoryBasic,
+           {syncable_prefs_ids::kDeleteBrowsingHistoryBasic,
+            syncer::PREFERENCES, PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {browsing_data::prefs::kDeleteCache,
+           {syncable_prefs_ids::kDeleteCache, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {browsing_data::prefs::kDeleteCacheBasic,
+           {syncable_prefs_ids::kDeleteCacheBasic, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {browsing_data::prefs::kDeleteCookies,
+           {syncable_prefs_ids::kDeleteCookies, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {browsing_data::prefs::kDeleteCookiesBasic,
+           {syncable_prefs_ids::kDeleteCookiesBasic, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {browsing_data::prefs::kDeleteDownloadHistory,
+           {syncable_prefs_ids::kDeleteDownloadHistory, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {browsing_data::prefs::kDeleteFormData,
+           {syncable_prefs_ids::kDeleteFormData, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {browsing_data::prefs::kDeleteHostedAppsData,
+           {syncable_prefs_ids::kDeleteHostedAppsData, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {browsing_data::prefs::kDeletePasswords,
+           {syncable_prefs_ids::kDeletePasswords, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {browsing_data::prefs::kDeleteSiteSettings,
+           {syncable_prefs_ids::kDeleteSiteSettings, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {browsing_data::prefs::kDeleteTimePeriod,
+           {syncable_prefs_ids::kDeleteTimePeriod, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {browsing_data::prefs::kDeleteTimePeriodBasic,
+           {syncable_prefs_ids::kDeleteTimePeriodBasic, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {browsing_data::prefs::kDeleteTimePeriodV2,
+           {syncable_prefs_ids::kDeleteTimePeriodV2, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {browsing_data::prefs::kDeleteTimePeriodV2Basic,
+           {syncable_prefs_ids::kDeleteTimePeriodV2Basic, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {browsing_data::prefs::kLastClearBrowsingDataTime,
+           {syncable_prefs_ids::kLastClearBrowsingDataTime, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {browsing_data::prefs::kPreferencesMigratedToBasic,
+           {syncable_prefs_ids::kPreferencesMigratedToBasic,
+            syncer::PREFERENCES, PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {commerce::kPriceEmailNotificationsEnabled,
+           {syncable_prefs_ids::kPriceEmailNotificationsEnabled,
+            syncer::PREFERENCES, PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {dom_distiller::prefs::kFont,
+           {syncable_prefs_ids::kFont, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {dom_distiller::prefs::kOfferReaderMode,
+           {syncable_prefs_ids::kOfferReaderMode, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {dom_distiller::prefs::kReaderForAccessibility,
+           {syncable_prefs_ids::kReaderForAccessibility, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {dom_distiller::prefs::kTheme,
+           {syncable_prefs_ids::kTheme, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {language::prefs::kAcceptLanguages,
+           {syncable_prefs_ids::kAcceptLanguages, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {language::prefs::kSelectedLanguages,
+           {syncable_prefs_ids::kSelectedLanguages, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {metrics::kSyncDemographicsPrefName,
+           {syncable_prefs_ids::kSyncDemographicsPrefName,
+            syncer::PRIORITY_PREFERENCES, PrefSensitivity::kNone,
+            MergeBehavior::kNone}},
+          {ntp_tiles::prefs::kCustomLinksInitialized,
+           {syncable_prefs_ids::kCustomLinksInitialized, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {ntp_tiles::prefs::kCustomLinksList,
+           {syncable_prefs_ids::kCustomLinksList, syncer::PREFERENCES,
+            PrefSensitivity::kSensitiveRequiresHistory, MergeBehavior::kNone}},
+          {omnibox::kKeywordSpaceTriggeringEnabled,
+           {syncable_prefs_ids::kKeywordSpaceTriggeringEnabled,
+            syncer::PREFERENCES, PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {password_manager::prefs::kCredentialsEnableAutosignin,
+           {syncable_prefs_ids::kCredentialsEnableAutosignin,
+            syncer::PRIORITY_PREFERENCES, PrefSensitivity::kNone,
+            MergeBehavior::kNone}},
+          {password_manager::prefs::kCredentialsEnableService,
+           {syncable_prefs_ids::kCredentialsEnableService,
+            syncer::PRIORITY_PREFERENCES, PrefSensitivity::kNone,
+            MergeBehavior::kNone}},
+          {password_manager::prefs::kPasswordDismissCompromisedAlertEnabled,
+           {syncable_prefs_ids::kPasswordDismissCompromisedAlertEnabled,
+            syncer::PREFERENCES, PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {password_manager::prefs::kPasswordLeakDetectionEnabled,
+           {syncable_prefs_ids::kPasswordLeakDetectionEnabled,
+            syncer::PREFERENCES, PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {password_manager::prefs::kSyncedLastTimePasswordCheckCompleted,
+           {syncable_prefs_ids::kSyncedLastTimePasswordCheckCompleted,
+            syncer::PRIORITY_PREFERENCES, PrefSensitivity::kNone,
+            MergeBehavior::kNone}},
+          {password_manager::prefs::kWasAutoSignInFirstRunExperienceShown,
+           {syncable_prefs_ids::kWasAutoSignInFirstRunExperienceShown,
+            syncer::PRIORITY_PREFERENCES, PrefSensitivity::kNone,
+            MergeBehavior::kNone}},
+          {payments::kCanMakePaymentEnabled,
+           {syncable_prefs_ids::kCanMakePaymentEnabled, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {prefs::kAccountTailoredSecurityUpdateTimestamp,
+           {syncable_prefs_ids::kAccountTailoredSecurityUpdateTimestamp,
+            syncer::PRIORITY_PREFERENCES, PrefSensitivity::kNone,
+            MergeBehavior::kNone}},
+          {prefs::kCookieControlsMode,
+           {syncable_prefs_ids::kCookieControlsMode, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {prefs::kSafeBrowsingEnabled,
+           {syncable_prefs_ids::kSafeBrowsingEnabled, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
 // TODO(crbug.com/1434910): Maybe move to chrome_syncable_prefs_database.cc,
 // see bug.
 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-        {prefs::kSyncedDefaultSearchProviderGUID,
-         {syncable_prefs_ids::kSyncedDefaultSearchProviderGUID,
-          syncer::PREFERENCES, PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {prefs::kSyncedDefaultSearchProviderGUID,
+           {syncable_prefs_ids::kSyncedDefaultSearchProviderGUID,
+            syncer::PREFERENCES, PrefSensitivity::kNone, MergeBehavior::kNone}},
 #endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-        {translate::TranslatePrefs::kPrefForceTriggerTranslateCount,
-         {syncable_prefs_ids::kPrefForceTriggerTranslateCount,
-          syncer::PREFERENCES, PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {translate::TranslatePrefs::kPrefTranslateAcceptedCount,
-         {syncable_prefs_ids::kPrefTranslateAcceptedCount, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {translate::TranslatePrefs::kPrefForceTriggerTranslateCount,
+           {syncable_prefs_ids::kPrefForceTriggerTranslateCount,
+            syncer::PREFERENCES, PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {translate::TranslatePrefs::kPrefTranslateAcceptedCount,
+           {syncable_prefs_ids::kPrefTranslateAcceptedCount,
+            syncer::PREFERENCES, PrefSensitivity::kNone, MergeBehavior::kNone}},
 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
-        {translate::TranslatePrefs::kPrefTranslateAutoAlwaysCount,
-         {syncable_prefs_ids::kPrefTranslateAutoAlwaysCount,
-          syncer::PREFERENCES, PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {translate::TranslatePrefs::kPrefTranslateAutoNeverCount,
-         {syncable_prefs_ids::kPrefTranslateAutoNeverCount, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {translate::TranslatePrefs::kPrefTranslateAutoAlwaysCount,
+           {syncable_prefs_ids::kPrefTranslateAutoAlwaysCount,
+            syncer::PREFERENCES, PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {translate::TranslatePrefs::kPrefTranslateAutoNeverCount,
+           {syncable_prefs_ids::kPrefTranslateAutoNeverCount,
+            syncer::PREFERENCES, PrefSensitivity::kNone, MergeBehavior::kNone}},
 #endif  // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
-        {translate::TranslatePrefs::kPrefTranslateDeniedCount,
-         {syncable_prefs_ids::kPrefTranslateDeniedCount, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {translate::prefs::kBlockedLanguages,
-         {syncable_prefs_ids::kBlockedLanguages, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {translate::prefs::kOfferTranslateEnabled,
-         {syncable_prefs_ids::kOfferTranslateEnabled, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {translate::prefs::kPrefAlwaysTranslateList,
-         {syncable_prefs_ids::kPrefAlwaysTranslateList, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {translate::prefs::kPrefNeverPromptSitesWithTime,
-         {syncable_prefs_ids::kPrefNeverPromptSitesWithTime,
-          syncer::PREFERENCES, PrefSensitivity::kSensitiveRequiresHistory,
-          MergeBehavior::kNone}},
-        {translate::prefs::kPrefTranslateRecentTarget,
-         {syncable_prefs_ids::kPrefTranslateRecentTarget, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {translate::TranslatePrefs::kPrefTranslateDeniedCount,
+           {syncable_prefs_ids::kPrefTranslateDeniedCount, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {translate::prefs::kBlockedLanguages,
+           {syncable_prefs_ids::kBlockedLanguages, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {translate::prefs::kOfferTranslateEnabled,
+           {syncable_prefs_ids::kOfferTranslateEnabled, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {translate::prefs::kPrefAlwaysTranslateList,
+           {syncable_prefs_ids::kPrefAlwaysTranslateList, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {translate::prefs::kPrefNeverPromptSitesWithTime,
+           {syncable_prefs_ids::kPrefNeverPromptSitesWithTime,
+            syncer::PREFERENCES, PrefSensitivity::kSensitiveRequiresHistory,
+            MergeBehavior::kNone}},
+          {translate::prefs::kPrefTranslateRecentTarget,
+           {syncable_prefs_ids::kPrefTranslateRecentTarget, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
 // For Ash, the OS_PRIORITY_PREFERENCES equivalent is defined in
 // chrome/browser/sync/prefs/chrome_syncable_prefs_database.cc instead.
 #if !BUILDFLAG(IS_CHROMEOS_ASH)
-        {variations::kDogfoodGroupsSyncPrefName,
-         {syncable_prefs_ids::kDogfoodGroupsSyncPrefName,
-          syncer::PRIORITY_PREFERENCES, PrefSensitivity::kNone,
-          MergeBehavior::kNone}},
+          {variations::kDogfoodGroupsSyncPrefName,
+           {syncable_prefs_ids::kDogfoodGroupsSyncPrefName,
+            syncer::PRIORITY_PREFERENCES, PrefSensitivity::kNone,
+            MergeBehavior::kNone}},
 #endif
-        {kSyncablePrefForTesting,
-         {syncable_prefs_ids::kSyncablePrefForTesting, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-        {kSyncableMergeableDictPrefForTesting,
-         {syncable_prefs_ids::kSyncableMergeableDictPrefForTesting,
-          syncer::PREFERENCES, PrefSensitivity::kNone,
-          MergeBehavior::kMergeableDict}},
-        {autofill::prefs::kAutofillPaymentCvcStorage,
-         {syncable_prefs_ids::kAutofillPaymentCvcStorage, syncer::PREFERENCES,
-          PrefSensitivity::kNone, MergeBehavior::kNone}},
-  });
+          {kSyncablePrefForTesting,
+           {syncable_prefs_ids::kSyncablePrefForTesting, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+          {kSyncableMergeableDictPrefForTesting,
+           {syncable_prefs_ids::kSyncableMergeableDictPrefForTesting,
+            syncer::PREFERENCES, PrefSensitivity::kNone,
+            MergeBehavior::kMergeableDict}},
+          {autofill::prefs::kAutofillPaymentCvcStorage,
+           {syncable_prefs_ids::kAutofillPaymentCvcStorage, syncer::PREFERENCES,
+            PrefSensitivity::kNone, MergeBehavior::kNone}},
+      });
   return kCommonSyncablePrefsAllowlist;
 }
 }  // namespace
diff --git a/components/viz/host/gpu_host_impl.cc b/components/viz/host/gpu_host_impl.cc
index 86e5ac36..1ddc650 100644
--- a/components/viz/host/gpu_host_impl.cc
+++ b/components/viz/host/gpu_host_impl.cc
@@ -536,8 +536,6 @@
     const absl::optional<gpu::GpuFeatureInfo>&
         gpu_feature_info_for_hardware_gpu,
     const gfx::GpuExtraInfo& gpu_extra_info) {
-  UMA_HISTOGRAM_BOOLEAN("GPU.GPUProcessInitialized", true);
-
   delegate_->DidInitialize(gpu_info, gpu_feature_info,
                            gpu_info_for_hardware_gpu,
                            gpu_feature_info_for_hardware_gpu, gpu_extra_info);
@@ -553,7 +551,6 @@
 }
 
 void GpuHostImpl::DidFailInitialize() {
-  UMA_HISTOGRAM_BOOLEAN("GPU.GPUProcessInitialized", false);
   delegate_->DidFailInitialize();
 }
 
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn
index 49974cf..12f99e26 100644
--- a/components/viz/service/BUILD.gn
+++ b/components/viz/service/BUILD.gn
@@ -465,7 +465,7 @@
   }
 
   if (skia_use_dawn) {
-    if (is_win) {
+    if (is_win || is_android) {
       sources += [
         "display_embedder/skia_output_device_dawn.cc",
         "display_embedder/skia_output_device_dawn.h",
diff --git a/components/viz/service/display_embedder/skia_output_device_dawn.cc b/components/viz/service/display_embedder/skia_output_device_dawn.cc
index 98159851..5727c41 100644
--- a/components/viz/service/display_embedder/skia_output_device_dawn.cc
+++ b/components/viz/service/display_embedder/skia_output_device_dawn.cc
@@ -17,8 +17,11 @@
 #include "ui/gfx/vsync_provider.h"
 #include "ui/gl/vsync_provider_win.h"
 
-namespace viz {
+#if BUILDFLAG(IS_ANDROID)
+#include "gpu/ipc/common/gpu_surface_lookup.h"
+#endif
 
+namespace viz {
 namespace {
 
 // TODO(crbug.com/dawn/286): Dawn requires that surface format is BGRA8Unorm for
@@ -65,6 +68,9 @@
   capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::BGRX_8888)] =
       kSurfaceColorType;
 
+  wgpu::SurfaceDescriptor surface_desc;
+
+#if BUILDFLAG(IS_WIN)
   gpu::SurfaceHandle window_handle_to_draw_to;
 
   // TODO(crbug.com/swiftshader/186): If we are using SwiftShader, don't create
@@ -85,10 +91,28 @@
   hwnd_desc.hwnd = window_handle_to_draw_to;
   hwnd_desc.hinstance = GetModuleHandle(nullptr);
 
+  surface_desc.nextInChain = &hwnd_desc;
+#endif
+
+#if BUILDFLAG(IS_ANDROID)
+  bool can_be_used_with_surface_control = false;
+  auto surface_variant =
+      gpu::GpuSurfaceLookup::GetInstance()->AcquireJavaSurface(
+          surface_handle, &can_be_used_with_surface_control);
+  // Should only reach here if surface control is disabled. In which case
+  // browser should not be sending ScopedJavaSurfaceControl variant.
+  CHECK(absl::holds_alternative<gl::ScopedJavaSurface>(surface_variant));
+  auto& scoped_java_surface = absl::get<gl::ScopedJavaSurface>(surface_variant);
+  android_native_window_ = gl::ScopedANativeWindow(scoped_java_surface);
+
+  wgpu::SurfaceDescriptorFromAndroidNativeWindow android_native_window_desc;
+  android_native_window_desc.window = android_native_window_.a_native_window();
+  surface_desc.nextInChain = &android_native_window_desc;
+#endif
+
   CHECK(context_state_->dawn_context_provider() &&
         context_state_->dawn_context_provider()->GetDevice());
-  wgpu::SurfaceDescriptor surface_desc;
-  surface_desc.nextInChain = &hwnd_desc;
+
   surface_ =
       context_state_->dawn_context_provider()->GetInstance().CreateSurface(
           &surface_desc);
@@ -101,10 +125,6 @@
 
 SkiaOutputDeviceDawn::~SkiaOutputDeviceDawn() = default;
 
-gpu::SurfaceHandle SkiaOutputDeviceDawn::GetChildSurfaceHandle() const {
-  return child_window_.window();
-}
-
 bool SkiaOutputDeviceDawn::Reshape(const SkImageInfo& image_info,
                                    const gfx::ColorSpace& color_space,
                                    int sample_count,
@@ -116,9 +136,11 @@
   sk_color_space_ = image_info.refColorSpace();
   sample_count_ = sample_count;
 
+#if BUILDFLAG(IS_WIN)
   if (child_window_.window() && !child_window_.Resize(size_)) {
     return false;
   }
+#endif
 
   wgpu::SwapChainDescriptor swap_chain_desc;
   swap_chain_desc.format = kSwapChainFormat;
@@ -165,7 +187,7 @@
   wgpu::Texture texture = swap_chain_.GetCurrentTexture();
   skgpu::graphite::BackendTexture backend_texture(texture.Get());
 
-  SkSurfaceProps surface_props{0, kUnknown_SkPixelGeometry};
+  SkSurfaceProps surface_props;
   sk_surface_ = SkSurfaces::WrapBackendTexture(
       context_state_->gpu_main_graphite_recorder(), backend_texture,
       kSurfaceColorType, sk_color_space_, &surface_props);
diff --git a/components/viz/service/display_embedder/skia_output_device_dawn.h b/components/viz/service/display_embedder/skia_output_device_dawn.h
index 11f00a6..75265b2 100644
--- a/components/viz/service/display_embedder/skia_output_device_dawn.h
+++ b/components/viz/service/display_embedder/skia_output_device_dawn.h
@@ -16,7 +16,14 @@
 #include "third_party/skia/include/core/SkImageInfo.h"
 #include "third_party/skia/include/gpu/GrBackendSurface.h"
 #include "ui/gfx/native_widget_types.h"
+
+#if BUILDFLAG(IS_WIN)
 #include "ui/gl/child_window_win.h"
+#endif
+
+#if BUILDFLAG(IS_ANDROID)
+#include "ui/gl/android/scoped_a_native_window.h"
+#endif
 
 namespace gpu {
 class SharedContextState;
@@ -38,7 +45,11 @@
 
   ~SkiaOutputDeviceDawn() override;
 
-  gpu::SurfaceHandle GetChildSurfaceHandle() const;
+#if BUILDFLAG(IS_WIN)
+  gpu::SurfaceHandle GetChildSurfaceHandle() const {
+    return child_window_.window();
+  }
+#endif
 
   // SkiaOutputDevice implementation:
   bool Reshape(const SkImageInfo& image_info,
@@ -65,12 +76,19 @@
   sk_sp<SkColorSpace> sk_color_space_;
   int sample_count_ = 1;
 
-  // D3D12 requires that we use flip model swap chains. Flip swap chains
-  // require that the swap chain be connected with DWM. DWM requires that
-  // the rendering windows are owned by the process that's currently doing
-  // the rendering. gl::ChildWindowWin creates and owns a window which is
-  // reparented by the browser to be a child of its window.
+#if BUILDFLAG(IS_WIN)
+  // D3D requires that we use flip model swap chains. Flip swap chains require
+  // that the swap chain be connected with DWM. DWM requires that the rendering
+  // windows are owned by the process that's currently doing the rendering.
+  // gl::ChildWindowWin creates and owns a window which is reparented by the
+  // browser to be a child of its window.
   gl::ChildWindowWin child_window_;
+#endif
+
+#if BUILDFLAG(IS_ANDROID)
+  // Use ScopedANativeWindow to keep the window alive
+  gl::ScopedANativeWindow android_native_window_;
+#endif
 };
 
 }  // namespace viz
diff --git a/components/viz/service/display_embedder/skia_output_device_dcomp.cc b/components/viz/service/display_embedder/skia_output_device_dcomp.cc
index 39d358b..24f663c 100644
--- a/components/viz/service/display_embedder/skia_output_device_dcomp.cc
+++ b/components/viz/service/display_embedder/skia_output_device_dcomp.cc
@@ -291,7 +291,7 @@
     base::debug::Alias(nullptr);
     return false;
   }
-  SkSurfaceProps surface_props{0, kUnknown_SkPixelGeometry};
+  SkSurfaceProps surface_props;
 
   GrGLFramebufferInfo framebuffer_info = {0};
   DCHECK_EQ(gl_surface_->GetBackingFramebufferObject(), 0u);
diff --git a/components/viz/service/display_embedder/skia_output_device_gl.cc b/components/viz/service/display_embedder/skia_output_device_gl.cc
index 8cf5010..a56342a 100644
--- a/components/viz/service/display_embedder/skia_output_device_gl.cc
+++ b/components/viz/service/display_embedder/skia_output_device_gl.cc
@@ -223,7 +223,7 @@
     base::debug::Alias(nullptr);
     return false;
   }
-  SkSurfaceProps surface_props{0, kUnknown_SkPixelGeometry};
+  SkSurfaceProps surface_props;
 
   GrGLFramebufferInfo framebuffer_info = {0};
   DCHECK_EQ(gl_surface_->GetBackingFramebufferObject(), 0u);
diff --git a/components/viz/service/display_embedder/skia_output_device_offscreen.cc b/components/viz/service/display_embedder/skia_output_device_offscreen.cc
index 49cf8f3ad..c687a429 100644
--- a/components/viz/service/display_embedder/skia_output_device_offscreen.cc
+++ b/components/viz/service/display_embedder/skia_output_device_offscreen.cc
@@ -161,7 +161,7 @@
     std::vector<GrBackendSemaphore>* end_semaphores) {
   DCHECK(backend_texture_.isValid() || graphite_texture_.isValid());
   if (!sk_surface_) {
-    SkSurfaceProps surface_props{0, kUnknown_SkPixelGeometry};
+    SkSurfaceProps surface_props;
     if (gr_context_) {
       sk_surface_ = SkSurfaces::WrapBackendTexture(
           context_state_->gr_context(), backend_texture_,
diff --git a/components/viz/service/display_embedder/skia_output_device_vulkan.cc b/components/viz/service/display_embedder/skia_output_device_vulkan.cc
index fae5e9b..576bf91458 100644
--- a/components/viz/service/display_embedder/skia_output_device_vulkan.cc
+++ b/components/viz/service/display_embedder/skia_output_device_vulkan.cc
@@ -192,7 +192,7 @@
       sk_surface_size_pairs_[scoped_write.image_index()].sk_surface;
 
   if (UNLIKELY(!sk_surface)) {
-    SkSurfaceProps surface_props{0, kUnknown_SkPixelGeometry};
+    SkSurfaceProps surface_props;
     const auto surface_format = vulkan_surface_->surface_format().format;
     DCHECK(surface_format == VK_FORMAT_B8G8R8A8_UNORM ||
            surface_format == VK_FORMAT_R8G8B8A8_UNORM);
diff --git a/components/viz/service/display_embedder/skia_output_device_webview.cc b/components/viz/service/display_embedder/skia_output_device_webview.cc
index e57bf75..bddc6dd 100644
--- a/components/viz/service/display_embedder/skia_output_device_webview.cc
+++ b/components/viz/service/display_embedder/skia_output_device_webview.cc
@@ -121,7 +121,7 @@
                     ? kTopLeft_GrSurfaceOrigin
                     : kBottomLeft_GrSurfaceOrigin;
 
-  SkSurfaceProps surface_props{0, kUnknown_SkPixelGeometry};
+  SkSurfaceProps surface_props;
   sk_surface_ = SkSurfaces::WrapBackendRenderTarget(
       context_state_->gr_context(), render_target, origin, color_type,
       sk_color_space_, &surface_props);
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl.cc b/components/viz/service/display_embedder/skia_output_surface_impl.cc
index 2ab8521..5a0c1695 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl.cc
@@ -1231,7 +1231,7 @@
   }
 
   auto cache_max_resource_bytes = impl_on_gpu_->max_resource_cache_bytes();
-  SkSurfaceProps surface_props{0, kUnknown_SkPixelGeometry};
+  SkSurfaceProps surface_props;
   const int sample_count = std::min(
       sample_count_,
       gr_context_thread_safe_->maxSurfaceSampleCountForColorType(color_type));
@@ -1280,7 +1280,7 @@
   }
 
   auto cache_max_resource_bytes = impl_on_gpu_->max_resource_cache_bytes();
-  SkSurfaceProps surface_props{0, kUnknown_SkPixelGeometry};
+  SkSurfaceProps surface_props;
   int sample_count = std::min(
       sample_count_,
       gr_context_thread_safe_->maxSurfaceSampleCountForColorType(color_type));
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
index d9fe792..13efccf 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -122,7 +122,7 @@
 
 #if BUILDFLAG(SKIA_USE_DAWN)
 #include "gpu/command_buffer/service/dawn_context_provider.h"
-#if BUILDFLAG(IS_WIN)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID)
 #include "components/viz/service/display_embedder/skia_output_device_dawn.h"
 #endif
 #endif
@@ -928,7 +928,7 @@
         return;
       }
 
-      SkSurfaceProps surface_props{0, kUnknown_SkPixelGeometry};
+      SkSurfaceProps surface_props;
       std::vector<GrBackendSemaphore> begin_semaphores;
       std::vector<GrBackendSemaphore> end_semaphores;
 
@@ -1111,7 +1111,7 @@
       return false;
     }
 
-    SkSurfaceProps surface_props{0, kUnknown_SkPixelGeometry};
+    SkSurfaceProps surface_props;
 
     std::unique_ptr<gpu::SkiaImageRepresentation::ScopedWriteAccess>
         scoped_write = representation->BeginScopedWriteAccess(
@@ -1169,7 +1169,7 @@
       return false;
     }
 
-    SkSurfaceProps surface_props{0, kUnknown_SkPixelGeometry};
+    SkSurfaceProps surface_props;
 
     std::unique_ptr<gpu::SkiaImageRepresentation::ScopedWriteAccess>
         scoped_write = representation->BeginScopedWriteAccess(
@@ -1665,7 +1665,7 @@
               mailbox, context_state_.get());
       DCHECK(backing_representation);
 
-      SkSurfaceProps surface_props{0, kUnknown_SkPixelGeometry};
+      SkSurfaceProps surface_props;
       // TODO(https://crbug.com/1226672): Use BeginScopedReadAccess instead
       scoped_access = backing_representation->BeginScopedWriteAccess(
           /*final_msaa_count=*/1, surface_props, &begin_semaphores,
@@ -2155,60 +2155,68 @@
         renderer_settings_.requires_alpha_channel,
         shared_gpu_deps_->memory_tracker(),
         GetDidSwapBuffersCompleteCallback());
-  } else {
+    return true;
+  }
+
 #if BUILDFLAG(IS_OZONE_X11)
-    // TODO(rivr): Set up a Vulkan swapchain so that Linux can also use
-    // SkiaOutputDeviceDawn.
-    if (MayFallBackToSkiaOutputDeviceX11()) {
-      output_device_ = SkiaOutputDeviceX11::Create(
-          context_state_, dependency_->GetSurfaceHandle(),
-          shared_gpu_deps_->memory_tracker(),
-          GetDidSwapBuffersCompleteCallback());
-    }
-#elif BUILDFLAG(IS_WIN)
-    presenter_ = dependency_->CreatePresenter(weak_ptr_factory_.GetWeakPtr());
-    if (presenter_) {
-      output_device_ = std::make_unique<SkiaOutputDeviceDCompPresenter>(
-          shared_image_representation_factory_.get(), context_state_.get(),
-          presenter_, feature_info_, shared_gpu_deps_->memory_tracker(),
-          GetDidSwapBuffersCompleteCallback());
-    } else {
-      auto output_device = std::make_unique<SkiaOutputDeviceDawn>(
-          context_state_, gfx::SurfaceOrigin::kTopLeft,
-          dependency_->GetSurfaceHandle(), shared_gpu_deps_->memory_tracker(),
-          GetDidSwapBuffersCompleteCallback());
-      if (output_device->GetChildSurfaceHandle()) {
-        AddChildWindowToBrowser(output_device->GetChildSurfaceHandle());
-      }
-      output_device_ = std::move(output_device);
-    }
-#elif BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_ANDROID)
-    presenter_ = dependency_->CreatePresenter(weak_ptr_factory_.GetWeakPtr());
-#if BUILDFLAG(IS_ANDROID)
-    // NOTE: The fallback case for SurfaceControl not being used is not yet
-    // supported.
-    // TODO(crbug.com/1505768): Get SkiaOutputDeviceDawn to work on Android and
-    // use it here if `presenter_` is null as is being done for Windows above.
-    CHECK(presenter_);
-#endif
-#if BUILDFLAG(IS_MAC)
-    if (features::UseGpuVsync()) {
-      presenter_->SetVSyncDisplayID(renderer_settings_.display_id);
-    }
-#endif  // BUILDFLAG(IS_MAC)
-    output_device_ = std::make_unique<SkiaOutputDeviceBufferQueue>(
-        std::make_unique<OutputPresenterGL>(
-            presenter_, dependency_, shared_image_factory_.get(),
-            shared_image_representation_factory_.get()),
-        dependency_, shared_image_representation_factory_.get(),
+  // TODO(rivr): Set up a Vulkan swapchain so that Linux can also use
+  // SkiaOutputDeviceDawn.
+  if (MayFallBackToSkiaOutputDeviceX11()) {
+    output_device_ = SkiaOutputDeviceX11::Create(
+        context_state_, dependency_->GetSurfaceHandle(),
         shared_gpu_deps_->memory_tracker(),
         GetDidSwapBuffersCompleteCallback());
-#else
-    NOTREACHED_NORETURN();
-#endif  // BUILDFLAG(IS_OZONE_X11)
+    return !!output_device_;
   }
+
+#elif BUILDFLAG(IS_WIN)
+  presenter_ = dependency_->CreatePresenter(weak_ptr_factory_.GetWeakPtr());
+  if (presenter_) {
+    output_device_ = std::make_unique<SkiaOutputDeviceDCompPresenter>(
+        shared_image_representation_factory_.get(), context_state_.get(),
+        presenter_, feature_info_, shared_gpu_deps_->memory_tracker(),
+        GetDidSwapBuffersCompleteCallback());
+  } else {
+    auto output_device = std::make_unique<SkiaOutputDeviceDawn>(
+        context_state_, gfx::SurfaceOrigin::kTopLeft,
+        dependency_->GetSurfaceHandle(), shared_gpu_deps_->memory_tracker(),
+        GetDidSwapBuffersCompleteCallback());
+    gpu::SurfaceHandle child_handle = output_device->GetChildSurfaceHandle();
+    if (child_handle != gpu::kNullSurfaceHandle) {
+      AddChildWindowToBrowser(child_handle);
+    }
+    output_device_ = std::move(output_device);
+  }
+  return true;
+
+#elif BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_ANDROID)
+  presenter_ = dependency_->CreatePresenter(weak_ptr_factory_.GetWeakPtr());
+
+#if BUILDFLAG(IS_ANDROID)
+  if (!presenter_) {
+    output_device_ = std::make_unique<SkiaOutputDeviceDawn>(
+        context_state_, gfx::SurfaceOrigin::kTopLeft,
+        dependency_->GetSurfaceHandle(), shared_gpu_deps_->memory_tracker(),
+        GetDidSwapBuffersCompleteCallback());
+    return true;
+  }
+#elif BUILDFLAG(IS_MAC)
+  if (features::UseGpuVsync()) {
+    presenter_->SetVSyncDisplayID(renderer_settings_.display_id);
+  }
+#endif  // BUILDFLAG(IS_MAC)
+
+  output_device_ = std::make_unique<SkiaOutputDeviceBufferQueue>(
+      std::make_unique<OutputPresenterGL>(
+          presenter_, dependency_, shared_image_factory_.get(),
+          shared_image_representation_factory_.get()),
+      dependency_, shared_image_representation_factory_.get(),
+      shared_gpu_deps_->memory_tracker(), GetDidSwapBuffersCompleteCallback());
+  return true;
+
+#endif  // BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_ANDROID)
 #endif  // BUILDFLAG(SKIA_USE_DAWN)
-  return !!output_device_;
+  NOTREACHED_NORETURN();
 }
 
 bool SkiaOutputSurfaceImplOnGpu::InitializeForMetal() {
diff --git a/components/webapps/common/android/BUILD.gn b/components/webapps/common/android/BUILD.gn
deleted file mode 100644
index 84fdbeeb..0000000
--- a/components/webapps/common/android/BUILD.gn
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright 2022 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/config/android/rules.gni")
-
-android_aidl("webapk_install_aidl") {
-  import_include = [ "java/src" ]
-  sources = [
-    "java/src/org/chromium/components/webapk_install/IOnFinishInstallCallback.aidl",
-    "java/src/org/chromium/components/webapk_install/IWebApkInstallCoordinatorService.aidl",
-  ]
-}
-
-android_library("webapk_install_java") {
-  srcjar_deps = [ ":webapk_install_aidl" ]
-}
diff --git a/components/webapps/common/android/java/src/org/chromium/components/webapk_install/IOnFinishInstallCallback.aidl b/components/webapps/common/android/java/src/org/chromium/components/webapk_install/IOnFinishInstallCallback.aidl
deleted file mode 100644
index e7010e11..0000000
--- a/components/webapps/common/android/java/src/org/chromium/components/webapk_install/IOnFinishInstallCallback.aidl
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.webapk_install;
-
-oneway interface IOnFinishInstallCallback {
-
-  void handleOnFinishInstall(int result);
-}
\ No newline at end of file
diff --git a/components/webapps/common/android/java/src/org/chromium/components/webapk_install/IWebApkInstallCoordinatorService.aidl b/components/webapps/common/android/java/src/org/chromium/components/webapk_install/IWebApkInstallCoordinatorService.aidl
deleted file mode 100644
index c0bdd9b..0000000
--- a/components/webapps/common/android/java/src/org/chromium/components/webapk_install/IWebApkInstallCoordinatorService.aidl
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.webapk_install;
-
-import org.chromium.components.webapk_install.IOnFinishInstallCallback;
-
-oneway interface IWebApkInstallCoordinatorService {
-
-    /**
-     * Schedule a WebAPK installation in the WebApkInstallCoordinatorService in Chrome.
-     * Chrome will handle the installation and invoke the {@code callback} when the
-     * installation succeeded or failed.
-     */
-    void scheduleInstallAsync(
-      in byte[] apkProto,
-      in Bitmap primaryIcon,
-      boolean isPrimaryIconMaskable,
-      IOnFinishInstallCallback callback
-    );
-}
diff --git a/components/webapps/common/android/java/src/org/chromium/components/webapk_install/OWNERS b/components/webapps/common/android/java/src/org/chromium/components/webapk_install/OWNERS
deleted file mode 100644
index 8f094e0..0000000
--- a/components/webapps/common/android/java/src/org/chromium/components/webapk_install/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-per-file *.aidl=set noparent
-per-file *.aidl=file://ipc/SECURITY_OWNERS
diff --git a/content/browser/accessibility/web_contents_accessibility_android.cc b/content/browser/accessibility/web_contents_accessibility_android.cc
index 654188d..02285ab0 100644
--- a/content/browser/accessibility/web_contents_accessibility_android.cc
+++ b/content/browser/accessibility/web_contents_accessibility_android.cc
@@ -789,7 +789,8 @@
       node->IsChecked(), node->IsClickable(), node->IsContentInvalid(),
       node->IsEnabled(), node->IsFocusable(), node->IsFocused(),
       node->HasImage(), node->IsPasswordField(), node->IsScrollable(),
-      node->IsSelected(), node->IsVisibleToUser());
+      node->IsSelected(), node->IsVisibleToUser(),
+      node->HasCharacterLocations());
 
   Java_AccessibilityNodeInfoBuilder_addAccessibilityNodeInfoActions(
       env, obj, info, unique_id, node->CanScrollForward(),
@@ -857,10 +858,6 @@
 
   UpdateAccessibilityNodeInfoBoundsRect(env, obj, info, unique_id, node);
 
-  Java_AccessibilityNodeInfoBuilder_setAccessibilityNodeInfoOAttributes(
-      env, obj, info, node->HasCharacterLocations(), node->HasImage(),
-      base::android::ConvertUTF16ToJavaString(env, node->GetHint()));
-
   if (node->IsCollection()) {
     Java_AccessibilityNodeInfoBuilder_setAccessibilityNodeInfoCollectionInfo(
         env, obj, info, node->RowCount(), node->ColumnCount(),
diff --git a/content/browser/indexed_db/indexed_db_bucket_context.cc b/content/browser/indexed_db/indexed_db_bucket_context.cc
index 38594d36..30ca7bf 100644
--- a/content/browser/indexed_db/indexed_db_bucket_context.cc
+++ b/content/browser/indexed_db/indexed_db_bucket_context.cc
@@ -14,10 +14,13 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/rand_util.h"
+#include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/task/thread_pool.h"
 #include "base/trace_event/base_tracing.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/process_memory_dump.h"
 #include "base/uuid.h"
 #include "build/build_config.h"
 #include "components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_database.h"
@@ -288,6 +291,12 @@
       blob_storage_context_(std::move(blob_storage_context)),
       file_system_access_context_(std::move(file_system_access_context)),
       delegate_(std::move(delegate)) {
+  // TODO(estade): is `SequencedTaskRunner::GetCurrentDefault()` actually safe?
+  base::trace_event::MemoryDumpManager::GetInstance()
+      ->RegisterDumpProviderWithSequencedTaskRunner(
+          this, "IndexedDBBucketContext",
+          base::SequencedTaskRunner::GetCurrentDefault(),
+          base::trace_event::MemoryDumpProvider::Options());
 
   backing_store_->set_bucket_context(this);
 
@@ -304,6 +313,8 @@
 
 IndexedDBBucketContext::~IndexedDBBucketContext() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
+      this);
   if (!backing_store_) {
     return;
   }
@@ -875,4 +886,28 @@
   file_reader_map_.erase(path);
 }
 
+bool IndexedDBBucketContext::OnMemoryDump(
+    const base::trace_event::MemoryDumpArgs& args,
+    base::trace_event::ProcessMemoryDump* pmd) {
+  base::CheckedNumeric<uint64_t> total_memory_in_flight = 0;
+  for (const auto& db_name_object_pair : databases()) {
+    for (IndexedDBConnection* connection :
+         db_name_object_pair.second->connections()) {
+      for (const auto& txn_id_pair : connection->transactions()) {
+        total_memory_in_flight += txn_id_pair.second->in_flight_memory();
+      }
+    }
+  }
+  // This pointer is used to match the pointer used in
+  // TransactionalLevelDBDatabase::OnMemoryDump.
+  leveldb::DB* db = backing_store()->db()->db();
+  auto* db_dump = pmd->CreateAllocatorDump(
+      base::StringPrintf("site_storage/index_db/in_flight_0x%" PRIXPTR,
+                         reinterpret_cast<uintptr_t>(db)));
+  db_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
+                     base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+                     total_memory_in_flight.ValueOrDefault(0));
+  return true;
+}
+
 }  // namespace content
diff --git a/content/browser/indexed_db/indexed_db_bucket_context.h b/content/browser/indexed_db/indexed_db_bucket_context.h
index dcf1b9d..4201f5a 100644
--- a/content/browser/indexed_db/indexed_db_bucket_context.h
+++ b/content/browser/indexed_db/indexed_db_bucket_context.h
@@ -18,6 +18,7 @@
 #include "base/sequence_checker.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
+#include "base/trace_event/memory_dump_provider.h"
 #include "components/services/storage/indexed_db/locks/partitioned_lock_manager.h"
 #include "components/services/storage/privileged/mojom/indexed_db_bucket_types.mojom.h"
 #include "components/services/storage/public/cpp/buckets/bucket_info.h"
@@ -63,7 +64,8 @@
 // as `IndexedDBFactory`, and those that pertain to a specific bucket and
 // therefore run on a bucket's IDB task runner, such as `IndexedDBDatabase` or
 // `IndexedDBCursor`.
-class CONTENT_EXPORT IndexedDBBucketContext {
+class CONTENT_EXPORT IndexedDBBucketContext
+    : public base::trace_event::MemoryDumpProvider {
  public:
   using DBMap =
       base::flat_map<std::u16string, std::unique_ptr<IndexedDBDatabase>>;
@@ -177,7 +179,7 @@
   IndexedDBBucketContext(const IndexedDBBucketContext&) = delete;
   IndexedDBBucketContext& operator=(const IndexedDBBucketContext&) = delete;
 
-  ~IndexedDBBucketContext();
+  ~IndexedDBBucketContext() override;
 
   void QueueRunTasks();
 
@@ -225,10 +227,15 @@
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     return backing_store_.get();
   }
+  // TODO(crbug.com/1474996): remove this.
   const DBMap& databases() const {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     return databases_;
   }
+  const DBMap& GetDatabasesForTesting() const {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    return databases_;
+  }
   PartitionedLockManager* lock_manager() {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     return lock_manager_.get();
@@ -272,6 +279,10 @@
 
   void CompactBackingStoreForTesting();
 
+  // base::trace_event::MemoryDumpProvider:
+  bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
+                    base::trace_event::ProcessMemoryDump* pmd) override;
+
  private:
   friend IndexedDBFactory;
   friend IndexedDBBucketContextHandle;
diff --git a/content/browser/indexed_db/indexed_db_database_unittest.cc b/content/browser/indexed_db/indexed_db_database_unittest.cc
index 5911dba6..74dc86d 100644
--- a/content/browser/indexed_db/indexed_db_database_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_database_unittest.cc
@@ -173,7 +173,7 @@
 
   RunPostedTasks();
 
-  EXPECT_TRUE(bucket_context_->databases().empty());
+  EXPECT_TRUE(bucket_context_->GetDatabasesForTesting().empty());
 }
 
 TEST_F(IndexedDBDatabaseTest, ForcedClose) {
diff --git a/content/browser/indexed_db/indexed_db_factory.cc b/content/browser/indexed_db/indexed_db_factory.cc
index 4a05fb4..fad29e7 100644
--- a/content/browser/indexed_db/indexed_db_factory.cc
+++ b/content/browser/indexed_db/indexed_db_factory.cc
@@ -26,15 +26,12 @@
 #include "base/ranges/algorithm.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/system/sys_info.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/timer/elapsed_timer.h"
 #include "base/timer/timer.h"
 #include "base/trace_event/base_tracing.h"
-#include "base/trace_event/memory_dump_manager.h"
-#include "base/trace_event/process_memory_dump.h"
 #include "components/services/storage/indexed_db/leveldb/leveldb_factory.h"
 #include "components/services/storage/indexed_db/scopes/leveldb_scopes.h"
 #include "components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_database.h"
@@ -174,17 +171,10 @@
 IndexedDBFactory::IndexedDBFactory(IndexedDBContextImpl* context)
     : context_(context) {
   DCHECK(context);
-  base::trace_event::MemoryDumpManager::GetInstance()
-      ->RegisterDumpProviderWithSequencedTaskRunner(
-          this, "IndexedDBFactory",
-          base::SequencedTaskRunner::GetCurrentDefault(),
-          base::trace_event::MemoryDumpProvider::Options());
 }
 
 IndexedDBFactory::~IndexedDBFactory() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
-      this);
 }
 
 void IndexedDBFactory::AddReceiver(
@@ -1001,33 +991,6 @@
   context_->DatabaseDeleted(bucket_locator);
 }
 
-bool IndexedDBFactory::OnMemoryDump(
-    const base::trace_event::MemoryDumpArgs& args,
-    base::trace_event::ProcessMemoryDump* pmd) {
-  for (const auto& bucket_context_pair : bucket_contexts_) {
-    IndexedDBBucketContext* bucket_context = bucket_context_pair.second.get();
-    base::CheckedNumeric<uint64_t> total_memory_in_flight = 0;
-    for (const auto& db_name_object_pair : bucket_context->databases()) {
-      for (IndexedDBConnection* connection :
-           db_name_object_pair.second->connections()) {
-        for (const auto& txn_id_pair : connection->transactions()) {
-          total_memory_in_flight += txn_id_pair.second->in_flight_memory();
-        }
-      }
-    }
-    // This pointer is used to match the pointer used in
-    // TransactionalLevelDBDatabase::OnMemoryDump.
-    leveldb::DB* db = bucket_context->backing_store()->db()->db();
-    auto* db_dump = pmd->CreateAllocatorDump(
-        base::StringPrintf("site_storage/index_db/in_flight_0x%" PRIXPTR,
-                           reinterpret_cast<uintptr_t>(db)));
-    db_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
-                       base::trace_event::MemoryAllocatorDump::kUnitsBytes,
-                       total_memory_in_flight.ValueOrDefault(0));
-  }
-  return true;
-}
-
 IndexedDBFactory::ReceiverContext::ReceiverContext(
     absl::optional<storage::BucketInfo> bucket,
     mojo::PendingRemote<storage::mojom::IndexedDBClientStateChecker>
diff --git a/content/browser/indexed_db/indexed_db_factory.h b/content/browser/indexed_db/indexed_db_factory.h
index 729c3e89..7a510a1 100644
--- a/content/browser/indexed_db/indexed_db_factory.h
+++ b/content/browser/indexed_db/indexed_db_factory.h
@@ -21,8 +21,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
 #include "base/time/time.h"
-#include "base/trace_event/memory_dump_provider.h"
-#include "components/services/storage/privileged/mojom/indexed_db_bucket_types.mojom.h"
 #include "components/services/storage/privileged/mojom/indexed_db_client_state_checker.mojom.h"
 #include "components/services/storage/public/cpp/buckets/bucket_id.h"
 #include "components/services/storage/public/cpp/buckets/bucket_info.h"
@@ -54,9 +52,7 @@
 
 // This class has a 1:1 relationship with `IndexedDBContextImpl`.
 // TODO(crbug.com/1474996): merge with `IndexedDBContextImpl`.
-class CONTENT_EXPORT IndexedDBFactory
-    : public blink::mojom::IDBFactory,
-      public base::trace_event::MemoryDumpProvider {
+class CONTENT_EXPORT IndexedDBFactory : public blink::mojom::IDBFactory {
  public:
   explicit IndexedDBFactory(IndexedDBContextImpl* context);
 
@@ -87,10 +83,6 @@
                       const std::u16string& name,
                       bool force_close) override;
 
-  // base::trace_event::MemoryDumpProvider:
-  bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
-                    base::trace_event::ProcessMemoryDump* pmd) override;
-
   // Close all connections to all databases within the bucket. If
   // `will_be_deleted` is true, references to in-memory databases will be
   // dropped thereby allowing their deletion (otherwise they are retained for
diff --git a/content/browser/indexed_db/indexed_db_factory_unittest.cc b/content/browser/indexed_db/indexed_db_factory_unittest.cc
index 5affcf3..52f53acb 100644
--- a/content/browser/indexed_db/indexed_db_factory_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_factory_unittest.cc
@@ -935,7 +935,8 @@
     IndexedDBBucketContext* bucket_context =
         factory()->GetBucketContextForTesting(bucket_locator.id);
     ASSERT_TRUE(bucket_context);
-    EXPECT_FALSE(base::Contains(bucket_context->databases(), db_name));
+    EXPECT_FALSE(
+        base::Contains(bucket_context->GetDatabasesForTesting(), db_name));
   }
 }
 
diff --git a/content/browser/interest_group/ad_auction_service_impl.cc b/content/browser/interest_group/ad_auction_service_impl.cc
index 706b4199..1612a78 100644
--- a/content/browser/interest_group/ad_auction_service_impl.cc
+++ b/content/browser/interest_group/ad_auction_service_impl.cc
@@ -33,12 +33,14 @@
 #include "content/browser/interest_group/ad_auction_result_metrics.h"
 #include "content/browser/interest_group/auction_runner.h"
 #include "content/browser/interest_group/auction_worklet_manager.h"
+#include "content/browser/interest_group/interest_group_features.h"
 #include "content/browser/interest_group/interest_group_manager_impl.h"
 #include "content/browser/private_aggregation/private_aggregation_manager.h"
 #include "content/browser/renderer_host/page_impl.h"
 #include "content/browser/renderer_host/render_frame_host_impl.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/cookie_deprecation_label_manager.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/common/content_client.h"
@@ -646,6 +648,23 @@
   return GetFrame()->BuildClientSecurityState();
 }
 
+absl::optional<std::string> AdAuctionServiceImpl::GetCookieDeprecationLabel() {
+  if (!base::FeatureList::IsEnabled(
+          features::kFledgeFacilitatedTestingSignalsHeaders)) {
+    return absl::nullopt;
+  }
+
+  CookieDeprecationLabelManager* cdlm =
+      render_frame_host()
+          .GetStoragePartition()
+          ->GetCookieDeprecationLabelManager();
+  if (cdlm) {
+    return cdlm->GetValue();
+  } else {
+    return absl::nullopt;
+  }
+}
+
 AdAuctionServiceImpl::AdAuctionServiceImpl(
     RenderFrameHost& render_frame_host,
     mojo::PendingReceiver<blink::mojom::AdAuctionService> receiver)
diff --git a/content/browser/interest_group/ad_auction_service_impl.h b/content/browser/interest_group/ad_auction_service_impl.h
index 364875a..e56e79e 100644
--- a/content/browser/interest_group/ad_auction_service_impl.h
+++ b/content/browser/interest_group/ad_auction_service_impl.h
@@ -105,6 +105,7 @@
   RenderFrameHostImpl* GetFrame() override;
   scoped_refptr<SiteInstance> GetFrameSiteInstance() override;
   network::mojom::ClientSecurityStatePtr GetClientSecurityState() override;
+  absl::optional<std::string> GetCookieDeprecationLabel() override;
 
   using DocumentService::origin;
   using DocumentService::render_frame_host;
diff --git a/content/browser/interest_group/ad_auction_service_impl_unittest.cc b/content/browser/interest_group/ad_auction_service_impl_unittest.cc
index dba97672..0715cde 100644
--- a/content/browser/interest_group/ad_auction_service_impl_unittest.cc
+++ b/content/browser/interest_group/ad_auction_service_impl_unittest.cc
@@ -108,6 +108,8 @@
 constexpr char kDecisionUrlPath[] = "/interest_group/decision_logic.js";
 constexpr char kTrustedBiddingSignalsUrlPath[] =
     "/interest_group/trusted_bidding_signals.json";
+constexpr char kTrustedScoringSignalsUrlPath[] =
+    "/interest_group/trusted_scoring_signals.json";
 constexpr char kUpdateUrlPath[] = "/interest_group/daily_update_partial.json";
 constexpr char kUpdateUrlPath2[] =
     "/interest_group/daily_update_partial_2.json";
@@ -230,6 +232,11 @@
     return allow_list_->contains(destination_origin);
   }
 
+  bool IsCookieDeprecationLabelAllowed(
+      content::BrowserContext* browser_context) override {
+    return true;
+  }
+
  private:
   // If not present, all origins are allowed.
   absl::optional<base::flat_set<url::Origin>> allow_list_;
@@ -249,6 +256,12 @@
     "HTTP/1.1 200 OK\n"
     "Ad-Auction-Allowed: true\n";
 
+constexpr char kFledgeSignalsHeaders[] =
+    "HTTP/1.1 200 OK\n"
+    "Content-type: Application/JSON\n"
+    "Data-Version: 2\n"
+    "Ad-Auction-Allowed: true\n";
+
 // Allows registering network responses to update and scoring / bidding script
 // requests; *must* be destroyed before the task environment is shutdown (which
 // happens in RenderViewHostTestHarness::TearDown()).
@@ -261,6 +274,9 @@
   using NetCallback =
       base::RepeatingCallback<void(URLLoaderInterceptor::RequestParams*)>;
 
+  using SignalsCallback = base::RepeatingCallback<std::string(
+      URLLoaderInterceptor::RequestParams*)>;
+
   // Register interest group update `response` to be served with JSON
   // content type when a request to `url_path` is made.
   void RegisterUpdateResponse(const std::string& url_path,
@@ -285,6 +301,14 @@
     report_map_[url_path] = response;
   }
 
+  // Register signals `response` to be served when a request to `url_path` is
+  // made.
+  void RegisterSignalsResponse(const std::string& url_path,
+                               SignalsCallback callback) {
+    base::AutoLock auto_lock(lock_);
+    signals_map_[url_path] = std::move(callback);
+  }
+
   // Register a repeat callback to be served when a request to `url_path` is
   // made.
   void RegisterRepeatCallback(const std::string& url_path,
@@ -474,6 +498,15 @@
       return true;
     }
 
+    // Check if it's a trusted bidding/scoring signals response.
+    const auto signals_it = signals_map_.find(params->url_request.url.path());
+    if (signals_it != signals_map_.end()) {
+      URLLoaderInterceptor::WriteResponse(kFledgeSignalsHeaders,
+                                          signals_it->second.Run(params),
+                                          params->client.get());
+      return true;
+    }
+
     if ((params->url_request.url.path() == store_url_loader_client_url_path_)) {
       CHECK(!stored_url_loader_client_);
       stored_url_loader_client_ = std::move(params->client);
@@ -571,6 +604,11 @@
   base::flat_map<std::string, std::string> report_map_ GUARDED_BY(lock_);
 
   // Like `json_update_map_`, but for registered callbacks that will be given
+  // the `URLLoaderInterceptor::RequestParams*` and return the response. Used
+  // for trusted signals requests.
+  base::flat_map<std::string, SignalsCallback> signals_map_ GUARDED_BY(lock_);
+
+  // Like `json_update_map_`, but for registered callbacks that will be given
   // the `URLLoaderInterceptor::RequestParams*`.
   base::flat_map<std::string, NetCallback> net_callback_map_ GUARDED_BY(lock_);
 
@@ -1115,6 +1153,8 @@
   const GURL kNewBiddingLogicUrlA = kUrlA.Resolve(kNewBiddingUrlPath);
   const GURL kTrustedBiddingSignalsUrlA =
       kUrlA.Resolve(kTrustedBiddingSignalsUrlPath);
+  const GURL kTrustedScoringSignalsUrlA =
+      kUrlA.Resolve(kTrustedScoringSignalsUrlPath);
   const GURL kUpdateUrlA = kUrlA.Resolve(kUpdateUrlPath);
   const GURL kUpdateUrlA2 = kUrlA.Resolve(kUpdateUrlPath2);
   const GURL kUpdateUrlA3 = kUrlA.Resolve(kUpdateUrlPath3);
@@ -6108,6 +6148,85 @@
               ::testing::UnorderedElementsAre(kOriginF, kOriginG));
 }
 
+// Like UpdatesInterestGroupsAfterSuccessfulAuction but
+// kFledgeDelayPostAuctionInterestGroupUpdate is enabled.
+TEST_F(AdAuctionServiceImplTest,
+       UpdatesInterestGroupsAfterSuccessfulAuctionDelayedUpdate) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(
+      features::kFledgeDelayPostAuctionInterestGroupUpdate);
+  constexpr char kBiddingScript[] = R"(
+function generateBid(
+    interestGroup, auctionSignals, perBuyerSignals, trustedBiddingSignals,
+    browserSignals) {
+  return {'ad': 'example', 'bid': 1, 'render': 'https://example.com/render'};
+}
+)";
+
+  constexpr char kDecisionScript[] = R"(
+function scoreAd(
+    adMetadata, bid, auctionConfig, trustedScoringSignals, browserSignals) {
+  return bid;
+}
+)";
+
+  content_browser_client_.SetAllowList({kOriginG, kOriginF});
+  network_responder_->RegisterUpdateResponse(kUpdateUrlPath, R"({
+"ads": [{
+  "renderURL": "https://example.com/new_render",
+  "allowedReportingOrigins":
+      ["https://g.test", "https://f.test", "https://g.test"]
+}]})");
+
+  network_responder_->RegisterScriptResponse(kBiddingUrlPath, kBiddingScript);
+  network_responder_->RegisterScriptResponse(kDecisionUrlPath, kDecisionScript);
+
+  blink::InterestGroup interest_group_a = CreateInterestGroup();
+  interest_group_a.update_url = kUpdateUrlA;
+  interest_group_a.bidding_url = kUrlA.Resolve(kBiddingUrlPath);
+  interest_group_a.ads.emplace();
+  blink::InterestGroup::Ad ad(
+      /*render_url=*/GURL("https://example.com/render"),
+      /*metadata=*/absl::nullopt);
+  interest_group_a.ads->emplace_back(std::move(ad));
+  JoinInterestGroupAndFlush(interest_group_a);
+  EXPECT_EQ(1, GetJoinCount(kOriginA, kInterestGroupName));
+
+  blink::AuctionConfig auction_config;
+  auction_config.seller = kOriginA;
+  auction_config.decision_logic_url = kUrlA.Resolve(kDecisionUrlPath);
+  auction_config.non_shared_params.interest_group_buyers = {kOriginA};
+  absl::optional<GURL> auction_result = RunAdAuctionAndFlush(auction_config);
+  ASSERT_NE(auction_result, absl::nullopt);
+  EXPECT_EQ(ConvertFencedFrameURNToURL(*auction_result),
+            GURL("https://example.com/render"));
+
+  // Now that the auction has completed, check that the interest group is
+  // updated after kPostAuctionInterestGroupUpdateDelay (but not before).
+  task_environment()->FastForwardBy(base::Seconds(1));
+
+  // The update shouldn't have happened yet.
+  auto a_groups = GetInterestGroupsForOwner(kOriginA);
+  ASSERT_EQ(a_groups->size(), 1u);
+  auto a_group = a_groups->GetInterestGroups()[0]->interest_group;
+  EXPECT_EQ(a_group.ads, interest_group_a.ads);
+
+  task_environment()->FastForwardBy(
+      AuctionRunner::kPostAuctionInterestGroupUpdateDelay);
+
+  // Now the update should have happened.
+  a_groups = GetInterestGroupsForOwner(kOriginA);
+  ASSERT_EQ(a_groups->size(), 1u);
+  a_group = a_groups->GetInterestGroups()[0]->interest_group;
+  ASSERT_TRUE(a_group.ads.has_value());
+  ASSERT_EQ(a_group.ads->size(), 1u);
+  EXPECT_EQ(a_group.ads.value()[0].render_url(),
+            "https://example.com/new_render");
+  ASSERT_TRUE(a_group.ads.value()[0].allowed_reporting_origins.has_value());
+  EXPECT_THAT(a_group.ads.value()[0].allowed_reporting_origins.value(),
+              ::testing::UnorderedElementsAre(kOriginF, kOriginG));
+}
+
 // Like UpdatesInterestGroupsAfterSuccessfulAuction, but the auction fails
 // because the scoring script always returns 0. The interest group should still
 // update.
@@ -12547,4 +12666,88 @@
                         0);
 }
 
+class AdAuctionServiceImplFacilitatedTestingTest
+    : public AdAuctionServiceImplTest {
+ public:
+  AdAuctionServiceImplFacilitatedTestingTest() {
+    features_.InitWithFeaturesAndParameters(
+        {{features::kCookieDeprecationFacilitatedTesting,
+          {{"label", "LabelForTesting"}}},
+         {features::kFledgeFacilitatedTestingSignalsHeaders, {}}},
+        {});
+  }
+
+ private:
+  base::test::ScopedFeatureList features_;
+};
+
+TEST_F(AdAuctionServiceImplFacilitatedTestingTest,
+       RunAdAuctionServesDeprecationLabelsInKVRequest) {
+  constexpr char kBiddingScript[] = R"(
+function generateBid(
+    interestGroup, auctionSignals, perBuyerSignals, trustedBiddingSignals,
+    browserSignals) {
+  return {'ad': 'example', 'bid': 1, 'render': 'https://example.com/render'};
+}
+)";
+
+  constexpr char kDecisionScript[] = R"(
+function scoreAd(
+    adMetadata, bid, auctionConfig, trustedScoringSignals, browserSignals) {
+  return bid;
+}
+)";
+
+  bool bidding_kv_called = false;
+  bool scoring_kv_called = false;
+  network_responder_->RegisterScriptResponse(kBiddingUrlPath, kBiddingScript);
+  network_responder_->RegisterScriptResponse(kDecisionUrlPath, kDecisionScript);
+  network_responder_->RegisterSignalsResponse(
+      kTrustedBiddingSignalsUrlPath,
+      base::BindLambdaForTesting(
+          [&](URLLoaderInterceptor::RequestParams* params) -> std::string {
+            std::string got_label;
+            EXPECT_TRUE(params->url_request.headers.GetHeader(
+                "Sec-Cookie-Deprecation", &got_label));
+            EXPECT_EQ("LabelForTesting", got_label);
+            bidding_kv_called = true;
+            return "{}";
+          }));
+  network_responder_->RegisterSignalsResponse(
+      kTrustedScoringSignalsUrlPath,
+      base::BindLambdaForTesting(
+          [&](URLLoaderInterceptor::RequestParams* params) -> std::string {
+            std::string got_label;
+            EXPECT_TRUE(params->url_request.headers.GetHeader(
+                "Sec-Cookie-Deprecation", &got_label));
+            EXPECT_EQ("LabelForTesting", got_label);
+            scoring_kv_called = true;
+            return "{}";
+          }));
+
+  blink::InterestGroup interest_group = CreateInterestGroup();
+  interest_group.bidding_url = kUrlA.Resolve(kBiddingUrlPath);
+  interest_group.trusted_bidding_signals_url = kTrustedBiddingSignalsUrlA;
+  interest_group.trusted_bidding_signals_keys = {"foo", "bar"};
+  interest_group.ads.emplace();
+  blink::InterestGroup::Ad ad(
+      /*render_url=*/GURL("https://example.com/render"),
+      /*metadata=*/absl::nullopt);
+  interest_group.ads->emplace_back(std::move(ad));
+  JoinInterestGroupAndFlush(interest_group);
+  EXPECT_EQ(1, GetJoinCount(kOriginA, kInterestGroupName));
+
+  blink::AuctionConfig auction_config;
+  auction_config.seller = kOriginA;
+  auction_config.decision_logic_url = kUrlA.Resolve(kDecisionUrlPath);
+  auction_config.trusted_scoring_signals_url = kTrustedScoringSignalsUrlA;
+  auction_config.non_shared_params.interest_group_buyers = {kOriginA};
+  absl::optional<GURL> auction_result = RunAdAuctionAndFlush(auction_config);
+  ASSERT_NE(auction_result, absl::nullopt);
+  EXPECT_EQ(ConvertFencedFrameURNToURL(*auction_result),
+            GURL("https://example.com/render"));
+  EXPECT_TRUE(bidding_kv_called);
+  EXPECT_TRUE(scoring_kv_called);
+}
+
 }  // namespace content
diff --git a/content/browser/interest_group/auction_runner.cc b/content/browser/interest_group/auction_runner.cc
index 99f48364..2aa071e 100644
--- a/content/browser/interest_group/auction_runner.cc
+++ b/content/browser/interest_group/auction_runner.cc
@@ -10,6 +10,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/feature_list.h"
 #include "base/functional/callback.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/strings/stringprintf.h"
@@ -612,8 +613,16 @@
         ContentBrowserClient::InterestGroupApiOperation::kUpdate, owner);
   });
 
-  interest_group_manager_->UpdateInterestGroupsOfOwners(
-      update_owners, client_security_state_.Clone(), attestation_callback_);
+  if (base::FeatureList::IsEnabled(
+          features::kFledgeDelayPostAuctionInterestGroupUpdate)) {
+    interest_group_manager_->UpdateInterestGroupsOfOwnersWithDelay(
+        std::move(update_owners), client_security_state_.Clone(),
+        std::move(attestation_callback_), kPostAuctionInterestGroupUpdateDelay);
+  } else {
+    interest_group_manager_->UpdateInterestGroupsOfOwners(
+        std::move(update_owners), client_security_state_.Clone(),
+        attestation_callback_);
+  }
 }
 
 void AuctionRunner::NotifyPromiseResolved(
diff --git a/content/browser/interest_group/auction_runner.h b/content/browser/interest_group/auction_runner.h
index e4ab440b..dc1442b 100644
--- a/content/browser/interest_group/auction_runner.h
+++ b/content/browser/interest_group/auction_runner.h
@@ -51,6 +51,11 @@
 // the code to assign unique tracing IDs is not threadsafe.
 class CONTENT_EXPORT AuctionRunner : public blink::mojom::AbortableAdAuction {
  public:
+  // After each auction, delay the update of interest groups so that data in the
+  // InterestGroupCachingStorage is not invalidated while a page's other
+  // auctions are likely still running.
+  static constexpr base::TimeDelta kPostAuctionInterestGroupUpdateDelay =
+      base::Seconds(3);
   using PrivateAggregationRequests =
       std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>;
 
diff --git a/content/browser/interest_group/auction_runner_unittest.cc b/content/browser/interest_group/auction_runner_unittest.cc
index 7420276..5d5aa06 100644
--- a/content/browser/interest_group/auction_runner_unittest.cc
+++ b/content/browser/interest_group/auction_runner_unittest.cc
@@ -2325,6 +2325,9 @@
   network::mojom::ClientSecurityStatePtr GetClientSecurityState() override {
     return network::mojom::ClientSecurityState::New();
   }
+  absl::optional<std::string> GetCookieDeprecationLabel() override {
+    return absl::nullopt;
+  }
 
   // DebuggableAuctionWorkletTracker::Observer implementation
   void AuctionWorkletCreated(DebuggableAuctionWorklet* worklet,
diff --git a/content/browser/interest_group/auction_url_loader_factory_proxy.cc b/content/browser/interest_group/auction_url_loader_factory_proxy.cc
index 6ce7619..64f1afa8 100644
--- a/content/browser/interest_group/auction_url_loader_factory_proxy.cc
+++ b/content/browser/interest_group/auction_url_loader_factory_proxy.cc
@@ -63,6 +63,7 @@
     GetUrlLoaderFactoryCallback get_frame_url_loader_factory,
     GetUrlLoaderFactoryCallback get_trusted_url_loader_factory,
     PreconnectSocketCallback preconnect_socket_callback,
+    GetCookieDeprecationLabelCallback get_cookie_deprecation_label,
     bool force_reload,
     const url::Origin& top_frame_origin,
     const url::Origin& frame_origin,
@@ -78,6 +79,7 @@
       get_frame_url_loader_factory_(std::move(get_frame_url_loader_factory)),
       get_trusted_url_loader_factory_(
           std::move(get_trusted_url_loader_factory)),
+      get_cookie_deprecation_label_(std::move(get_cookie_deprecation_label)),
       top_frame_origin_(top_frame_origin),
       frame_origin_(frame_origin),
       renderer_process_id_(renderer_process_id),
@@ -189,6 +191,15 @@
   new_request.request_initiator = frame_origin_;
   new_request.enable_load_timing = url_request.enable_load_timing;
 
+  if (is_trusted_bidding_signals_request) {
+    absl::optional<std::string> maybe_deprecation_label =
+        get_cookie_deprecation_label_.Run();
+    if (maybe_deprecation_label) {
+      new_request.headers.SetHeader("Sec-Cookie-Deprecation",
+                                    *maybe_deprecation_label);
+    }
+  }
+
   if (force_reload_) {
     new_request.load_flags = net::LOAD_BYPASS_CACHE;
   }
diff --git a/content/browser/interest_group/auction_url_loader_factory_proxy.h b/content/browser/interest_group/auction_url_loader_factory_proxy.h
index 672dc50..cced2a84 100644
--- a/content/browser/interest_group/auction_url_loader_factory_proxy.h
+++ b/content/browser/interest_group/auction_url_loader_factory_proxy.h
@@ -45,6 +45,9 @@
       const GURL& url,
       const net::NetworkAnonymizationKey& network_anonymization_key)>;
 
+  using GetCookieDeprecationLabelCallback =
+      base::RepeatingCallback<absl::optional<std::string>()>;
+
   // Passed in callbacks must be safe to call at any time during the lifetime of
   // the AuctionURLLoaderFactoryProxy.
   //
@@ -91,6 +94,7 @@
       GetUrlLoaderFactoryCallback get_frame_url_loader_factory,
       GetUrlLoaderFactoryCallback get_trusted_url_loader_factory,
       PreconnectSocketCallback preconnect_socket_callback,
+      GetCookieDeprecationLabelCallback get_cookie_deprecation_label,
       bool force_reload,
       const url::Origin& top_frame_origin,
       const url::Origin& frame_origin,
@@ -159,6 +163,7 @@
 
   const GetUrlLoaderFactoryCallback get_frame_url_loader_factory_;
   const GetUrlLoaderFactoryCallback get_trusted_url_loader_factory_;
+  const GetCookieDeprecationLabelCallback get_cookie_deprecation_label_;
 
   // Manages the bundle subresource URLs that may be accessed by the worklet.
   SubresourceUrlAuthorizations subresource_url_authorizations_;
diff --git a/content/browser/interest_group/auction_url_loader_factory_proxy_unittest.cc b/content/browser/interest_group/auction_url_loader_factory_proxy_unittest.cc
index 35ed587..f37777a 100644
--- a/content/browser/interest_group/auction_url_loader_factory_proxy_unittest.cc
+++ b/content/browser/interest_group/auction_url_loader_factory_proxy_unittest.cc
@@ -132,6 +132,8 @@
             &trusted_url_loader_factory_),
         base::BindOnce(&AuctionUrlLoaderFactoryProxyTest::PreconnectSocket,
                        base::Unretained(this)),
+        base::BindRepeating(
+            []() -> absl::optional<std::string> { return absl::nullopt; }),
         /*force_reload=*/force_reload_, top_frame_origin_, frame_origin_,
         /*renderer_process_id=*/kRenderProcessId, is_for_seller_,
         client_security_state_.Clone(), GURL(kScriptUrl), wasm_url_,
diff --git a/content/browser/interest_group/auction_worklet_manager.cc b/content/browser/interest_group/auction_worklet_manager.cc
index 1005720..8a710c1 100644
--- a/content/browser/interest_group/auction_worklet_manager.cc
+++ b/content/browser/interest_group/auction_worklet_manager.cc
@@ -341,6 +341,8 @@
       base::BindRepeating(&Delegate::GetTrustedURLLoaderFactory,
                           base::Unretained(delegate)),
       base::BindOnce(&Delegate::PreconnectSocket, base::Unretained(delegate)),
+      base::BindRepeating(&Delegate::GetCookieDeprecationLabel,
+                          base::Unretained(delegate)),
       /*force_reload=*/rfh->reload_type() == ReloadType::BYPASSING_CACHE,
       worklet_manager_->top_window_origin(), worklet_manager_->frame_origin(),
       // NOTE: `rfh` can be null in tests.
diff --git a/content/browser/interest_group/auction_worklet_manager.h b/content/browser/interest_group/auction_worklet_manager.h
index c5fc2ba4..efbd354 100644
--- a/content/browser/interest_group/auction_worklet_manager.h
+++ b/content/browser/interest_group/auction_worklet_manager.h
@@ -107,6 +107,9 @@
     // Returns the ClientSecurityState associated with the frame, for use in
     // bidder worklet and signals fetches.
     virtual network::mojom::ClientSecurityStatePtr GetClientSecurityState() = 0;
+
+    // Returns the cookie deprecation label for facilitated testing.
+    virtual absl::optional<std::string> GetCookieDeprecationLabel() = 0;
   };
 
   // Internal class that owns and creates worklets. It also tracks pending
diff --git a/content/browser/interest_group/auction_worklet_manager_unittest.cc b/content/browser/interest_group/auction_worklet_manager_unittest.cc
index 960d8fc..690403d 100644
--- a/content/browser/interest_group/auction_worklet_manager_unittest.cc
+++ b/content/browser/interest_group/auction_worklet_manager_unittest.cc
@@ -694,6 +694,9 @@
   network::mojom::ClientSecurityStatePtr GetClientSecurityState() override {
     return network::mojom::ClientSecurityState::New();
   }
+  absl::optional<std::string> GetCookieDeprecationLabel() override {
+    return absl::nullopt;
+  }
 
  protected:
   void OnBadMessage(const std::string& reason) {
diff --git a/content/browser/interest_group/interest_group_auction_reporter_unittest.cc b/content/browser/interest_group/interest_group_auction_reporter_unittest.cc
index 6a4a61b..130d3ef 100644
--- a/content/browser/interest_group/interest_group_auction_reporter_unittest.cc
+++ b/content/browser/interest_group/interest_group_auction_reporter_unittest.cc
@@ -409,6 +409,9 @@
   network::mojom::ClientSecurityStatePtr GetClientSecurityState() override {
     return frame_client_security_state_.Clone();
   }
+  absl::optional<std::string> GetCookieDeprecationLabel() override {
+    return absl::nullopt;
+  }
 
   void WaitForCompletion() { WaitForCompletionExpectingErrors({}); }
 
diff --git a/content/browser/interest_group/interest_group_browsertest.cc b/content/browser/interest_group/interest_group_browsertest.cc
index 2a7b942..f7876cf 100644
--- a/content/browser/interest_group/interest_group_browsertest.cc
+++ b/content/browser/interest_group/interest_group_browsertest.cc
@@ -696,7 +696,8 @@
          features::kBackForwardCache, features::kFledgeUseInterestGroupCache},
         /*disabled_features=*/
         {blink::features::kFencedFrames,
-         blink::features::kFledgeEnforceKAnonymity});
+         blink::features::kFledgeEnforceKAnonymity,
+         features::kCookieDeprecationFacilitatedTesting});
   }
 
   ~InterestGroupBrowserTest() override { content_browser_client_.reset(); }
diff --git a/content/browser/interest_group/interest_group_features.cc b/content/browser/interest_group/interest_group_features.cc
index 037ec39..7c4e93d6 100644
--- a/content/browser/interest_group/interest_group_features.cc
+++ b/content/browser/interest_group/interest_group_features.cc
@@ -27,4 +27,8 @@
              "EnableUpdatingUserBiddingSignals",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kFledgeFacilitatedTestingSignalsHeaders,
+             "FledgeFacilitatedTestingSignalsHeaders",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 }  // namespace features
diff --git a/content/browser/interest_group/interest_group_features.h b/content/browser/interest_group/interest_group_features.h
index b3cc2ce..155c9668 100644
--- a/content/browser/interest_group/interest_group_features.h
+++ b/content/browser/interest_group/interest_group_features.h
@@ -18,6 +18,8 @@
     kEnableUpdatingExecutionModeToFrozenContext);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kEnableUpdatingUserBiddingSignals);
 
+CONTENT_EXPORT BASE_DECLARE_FEATURE(kFledgeFacilitatedTestingSignalsHeaders);
+
 }  // namespace features
 
 #endif  // CONTENT_BROWSER_INTEREST_GROUP_INTEREST_GROUP_FEATURES_H_
diff --git a/content/browser/interest_group/interest_group_manager_impl.cc b/content/browser/interest_group/interest_group_manager_impl.cc
index 34bb9b6..0a3e642 100644
--- a/content/browser/interest_group/interest_group_manager_impl.cc
+++ b/content/browser/interest_group/interest_group_manager_impl.cc
@@ -319,13 +319,26 @@
 }
 
 void InterestGroupManagerImpl::UpdateInterestGroupsOfOwners(
-    base::span<url::Origin> owners,
+    std::vector<url::Origin> owners,
     network::mojom::ClientSecurityStatePtr client_security_state,
     AreReportingOriginsAttestedCallback callback) {
   update_manager_.UpdateInterestGroupsOfOwners(
       owners, std::move(client_security_state), std::move(callback));
 }
 
+void InterestGroupManagerImpl::UpdateInterestGroupsOfOwnersWithDelay(
+    std::vector<url::Origin> owners,
+    network::mojom::ClientSecurityStatePtr client_security_state,
+    AreReportingOriginsAttestedCallback callback,
+    const base::TimeDelta& delay) {
+  base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(&InterestGroupManagerImpl::UpdateInterestGroupsOfOwners,
+                     weak_factory_.GetWeakPtr(), std::move(owners),
+                     std::move(client_security_state), std::move(callback)),
+      delay);
+}
+
 void InterestGroupManagerImpl::RecordInterestGroupBids(
     const blink::InterestGroupSet& group_keys) {
   if (group_keys.empty()) {
diff --git a/content/browser/interest_group/interest_group_manager_impl.h b/content/browser/interest_group/interest_group_manager_impl.h
index 5fb798f4..6ab0b5e6 100644
--- a/content/browser/interest_group/interest_group_manager_impl.h
+++ b/content/browser/interest_group/interest_group_manager_impl.h
@@ -206,10 +206,16 @@
   //
   // The list is shuffled in-place to ensure fairness.
   void UpdateInterestGroupsOfOwners(
-      base::span<url::Origin> owners,
+      std::vector<url::Origin> owners,
       network::mojom::ClientSecurityStatePtr client_security_state,
       AreReportingOriginsAttestedCallback callback);
 
+  void UpdateInterestGroupsOfOwnersWithDelay(
+      std::vector<url::Origin> owners,
+      network::mojom::ClientSecurityStatePtr client_security_state,
+      AreReportingOriginsAttestedCallback callback,
+      const base::TimeDelta& delay);
+
   // For testing *only*; changes the maximum amount of time that the update
   // process can run before it gets cancelled for taking too long.
   void set_max_update_round_duration_for_testing(base::TimeDelta delta) {
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index 3110edc..bceffd4 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -5583,7 +5583,7 @@
 
   DetermineOriginAgentClusterEndResult();
 
-  UpdateCommitNavigationParamsHistory();
+  UpdateHistoryParamsInCommitNavigationParams();
 
   common_params_->should_replace_current_entry =
       ShouldReplaceCurrentEntryForFailedNavigation();
@@ -5680,7 +5680,7 @@
 
   DetermineOriginAgentClusterEndResult();
 
-  UpdateCommitNavigationParamsHistory();
+  UpdateHistoryParamsInCommitNavigationParams();
   DCHECK(NeedsUrlLoader() == !!response_head_ ||
          (was_redirected_ && common_params_->url.IsAboutBlank()));
   DCHECK(!common_params_->url.SchemeIs(url::kJavaScriptScheme));
@@ -5689,8 +5689,6 @@
   AddOldPageInfoToCommitParamsIfNeeded();
 
   url::Origin origin = GetOriginToCommit().value();
-  // TODO(crbug.com/979296): Consider changing this code to copy an origin
-  // instead of creating one from a URL which lacks opacity information.
   isolation_info_for_subresources_ =
       GetRenderFrameHost()->ComputeIsolationInfoForSubresourcesForPendingCommit(
           origin, is_credentialless(), ComputeFencedFrameNonce());
@@ -6573,7 +6571,7 @@
   return CSPEmbeddedEnforcementResult::BLOCK_RESPONSE;
 }
 
-void NavigationRequest::UpdateCommitNavigationParamsHistory() {
+void NavigationRequest::UpdateHistoryParamsInCommitNavigationParams() {
   NavigationController& navigation_controller =
       frame_tree_node_->navigator().controller();
   commit_params_->current_history_list_offset =
diff --git a/content/browser/renderer_host/navigation_request.h b/content/browser/renderer_host/navigation_request.h
index da8a409c..de6505c 100644
--- a/content/browser/renderer_host/navigation_request.h
+++ b/content/browser/renderer_host/navigation_request.h
@@ -1611,7 +1611,7 @@
   // Called before a commit. Updates the history index and length held in
   // CommitNavigationParams. This is used to update this shared state with the
   // renderer process.
-  void UpdateCommitNavigationParamsHistory();
+  void UpdateHistoryParamsInCommitNavigationParams();
 
   // The disconnect handler for the NavigationClient Mojo interface; used as a
   // signal to potentially cancel navigations, e.g. when the renderer replaces
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index cb0b414..077a3c49 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -715,9 +715,8 @@
 }
 
 // Verify that |browser_side_origin| and |renderer_side_origin| match.  See also
-// https://crbug.com/888079. Returns true if the origins match, and false
-// otherwise.
-bool VerifyThatBrowserAndRendererCalculatedOriginsToCommitMatch(
+// https://crbug.com/888079.
+void VerifyThatBrowserAndRendererCalculatedOriginsToCommitMatch(
     NavigationRequest* navigation_request,
     const mojom::DidCommitProvisionalLoadParams& params) {
   DCHECK(navigation_request);
@@ -732,7 +731,7 @@
   // NavigationBrowserTest.OpenerNavigation_DownloadPolicy,
   // WebContentsImplBrowserTest.NewNamedWindow.
   if (navigation_request->state() < NavigationRequest::WILL_PROCESS_RESPONSE)
-    return true;
+    return;
 
   // Blob urls with content scheme are opaque on browser side because the
   // browser doesn't have access to the BlobURLNullOriginMap.
@@ -743,7 +742,7 @@
           navigation_request->GetOriginToCommitWithDebugInfo();
   if (renderer_side_origin.scheme() == url::kContentScheme &&
       browser_side_origin_and_debug_info.first->opaque()) {
-    return true;
+    return;
   }
 
   // For non-opaque origins, we say the browser and renderer calculated origins
@@ -791,35 +790,12 @@
     DCHECK_EQ(browser_side_origin_and_debug_info.first.value(),
               renderer_side_origin)
         << "; navigation_request->GetURL() = " << navigation_request->GetURL();
-    return false;
+    return;
   }
 
-  return true;
+  return;
 }
 
-// Enum used for Navigation.VerifyDidCommitParams histogram, to indicate which
-// DidCommitProvisionalLoadParams differ when comparing browser- vs
-// renderer-calculated values.
-// Do NOT delete or reorder existing entries.
-enum class VerifyDidCommitParamsDifference {
-  kIntendedAsNewEntry = 0,
-  kMethod = 1,
-  kURLIsUnreachable = 2,
-  kBaseURL = 3,
-  kPostID = 4,
-  kIsOverridingUserAgent = 5,
-  kHTTPStatusCode = 6,
-  kShouldUpdateHistory = 7,
-  kGesture = 8,
-  kShouldReplaceCurrentEntry = 9,
-  kURL = 10,
-  kDidCreateNewEntry = 11,
-  kTransition = 12,
-  kHistoryListWasCleared = 13,
-  kOrigin = 14,
-  kMaxValue = kOrigin,
-};
-
 // A simplified version of Blink's WebFrameLoadType, used to simulate renderer
 // calculations. See CalculateRendererLoadType() further below.
 // TODO(https://crbug.com/1131832): This should only be here temporarily.
@@ -14643,11 +14619,6 @@
 #endif
 }
 
-void LogVerifyDidCommitParamsDifference(
-    VerifyDidCommitParamsDifference difference) {
-  UMA_HISTOGRAM_ENUMERATION("Navigation.VerifyDidCommitParams", difference);
-}
-
 std::string GetURLTypeForCrashKey(const GURL& url) {
   if (url == kUnreachableWebDataURL)
     return "error";
@@ -14995,55 +14966,9 @@
                                                      params.transition));
   DCHECK_EQ(browser_history_list_was_cleared, params.history_list_was_cleared);
 
-  // Log histograms to trigger Chrometto slow reports, allowing us to see traces
-  // to analyze what happened in these navigations.
-  if (browser_method != params.method) {
-    LogVerifyDidCommitParamsDifference(
-        VerifyDidCommitParamsDifference::kMethod);
-  }
-  if (browser_url_is_unreachable != params.url_is_unreachable) {
-    LogVerifyDidCommitParamsDifference(
-        VerifyDidCommitParamsDifference::kURLIsUnreachable);
-  }
-  if (browser_post_id != params.post_id) {
-    LogVerifyDidCommitParamsDifference(
-        VerifyDidCommitParamsDifference::kPostID);
-  }
-  if (browser_is_overriding_user_agent != params.is_overriding_user_agent) {
-    LogVerifyDidCommitParamsDifference(
-        VerifyDidCommitParamsDifference::kIsOverridingUserAgent);
-  }
-  if (browser_http_status_code != params.http_status_code) {
-    LogVerifyDidCommitParamsDifference(
-        VerifyDidCommitParamsDifference::kHTTPStatusCode);
-  }
-  if (browser_should_update_history != params.should_update_history) {
-    LogVerifyDidCommitParamsDifference(
-        VerifyDidCommitParamsDifference::kShouldUpdateHistory);
-  }
-  if (browser_url != params.url) {
-    LogVerifyDidCommitParamsDifference(VerifyDidCommitParamsDifference::kURL);
-  }
-  if (browser_did_create_new_entry != params.did_create_new_entry) {
-    LogVerifyDidCommitParamsDifference(
-        VerifyDidCommitParamsDifference::kDidCreateNewEntry);
-  }
-  if (!ui::PageTransitionTypeIncludingQualifiersIs(browser_transition,
-                                                   params.transition)) {
-    LogVerifyDidCommitParamsDifference(
-        VerifyDidCommitParamsDifference::kTransition);
-  }
-  if (browser_history_list_was_cleared != params.history_list_was_cleared) {
-    LogVerifyDidCommitParamsDifference(
-        VerifyDidCommitParamsDifference::kHistoryListWasCleared);
-  }
   // TODO(https://crbug.com/888079): The origin computed from the browser must
   // match the one reported from the renderer process.
-  if (!VerifyThatBrowserAndRendererCalculatedOriginsToCommitMatch(request,
-                                                                  params)) {
-    LogVerifyDidCommitParamsDifference(
-        VerifyDidCommitParamsDifference::kOrigin);
-  }
+  VerifyThatBrowserAndRendererCalculatedOriginsToCommitMatch(request, params);
 
   if (!everything_except_origin_matches) {
     // It's possible to get here when everything except the origin matches.
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index be3b154..84c0613 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -4368,8 +4368,7 @@
                "opener", opener, "params", params);
   DCHECK(opener);
 
-  if (base::FeatureList::IsEnabled(features::kWindowOpenFileSelectFix) &&
-      active_file_chooser_) {
+  if (active_file_chooser_) {
     // Do not allow opening a new window or tab while a file select is active
     // file chooser to avoid user confusion over which tab triggered the file
     // chooser.
@@ -6940,15 +6939,13 @@
   base::ScopedClosureRunner cancel_chooser(base::BindOnce(
       &FileChooserImpl::FileSelectListenerImpl::FileSelectionCanceled,
       listener));
-  if (base::FeatureList::IsEnabled(features::kWindowOpenFileSelectFix)) {
-    if (visibility_ == Visibility::HIDDEN) {
-      // Do not allow background tab to open file chooser.
-      return;
-    }
-    if (active_file_chooser_) {
-      // Only allow one active file chooser at one time.
-      return;
-    }
+  if (visibility_ == Visibility::HIDDEN) {
+    // Do not allow background tab to open file chooser.
+    return;
+  }
+  if (active_file_chooser_) {
+    // Only allow one active file chooser at one time.
+    return;
   }
 
   // Any explicit focusing of another window while this WebContents is in
@@ -6957,9 +6954,7 @@
   listener->SetFullscreenBlock(std::move(fullscreen_block));
 
   if (delegate_) {
-    if (base::FeatureList::IsEnabled(features::kWindowOpenFileSelectFix)) {
-      active_file_chooser_ = std::move(file_chooser);
-    }
+    active_file_chooser_ = std::move(file_chooser);
     delegate_->EnumerateDirectory(this, std::move(listener), directory_path);
     std::ignore = cancel_chooser.Release();
   }
@@ -7732,15 +7727,13 @@
   base::ScopedClosureRunner cancel_chooser(base::BindOnce(
       &FileChooserImpl::FileSelectListenerImpl::FileSelectionCanceled,
       listener));
-  if (base::FeatureList::IsEnabled(features::kWindowOpenFileSelectFix)) {
-    if (visibility_ == Visibility::HIDDEN) {
-      // Do not allow background tab to open file chooser.
-      return;
-    }
-    if (active_file_chooser_) {
-      // Only allow one active file chooser at one time.
-      return;
-    }
+  if (visibility_ == Visibility::HIDDEN) {
+    // Do not allow background tab to open file chooser.
+    return;
+  }
+  if (active_file_chooser_) {
+    // Only allow one active file chooser at one time.
+    return;
   }
 
   // Any explicit focusing of another window while this WebContents is in
@@ -7749,9 +7742,7 @@
   listener->SetFullscreenBlock(std::move(fullscreen_block));
 
   if (delegate_) {
-    if (base::FeatureList::IsEnabled(features::kWindowOpenFileSelectFix)) {
-      active_file_chooser_ = std::move(file_chooser);
-    }
+    active_file_chooser_ = std::move(file_chooser);
     delegate_->RunFileChooser(render_frame_host, std::move(listener), params);
     std::ignore = cancel_chooser.Release();
   }
diff --git a/content/browser/webid/federated_auth_disconnect_request.cc b/content/browser/webid/federated_auth_disconnect_request.cc
index d28f52ec..bf0d9d5 100644
--- a/content/browser/webid/federated_auth_disconnect_request.cc
+++ b/content/browser/webid/federated_auth_disconnect_request.cc
@@ -17,7 +17,7 @@
 using FederatedApiPermissionStatus =
     FederatedIdentityApiPermissionContextDelegate::PermissionStatus;
 using LoginState = IdentityRequestAccount::LoginState;
-using DisconnectStatusForMetrics = content::FedCmDisconnectStatus;
+using DisconnectStatusForMetrics = FedCmDisconnectStatus;
 using blink::mojom::DisconnectStatus;
 using blink::mojom::FederatedAuthRequestResult;
 
@@ -237,10 +237,13 @@
 
 void FederatedAuthDisconnectRequest::Complete(
     blink::mojom::DisconnectStatus status,
-    content::FedCmDisconnectStatus disconnect_status_for_metrics) {
+    FedCmDisconnectStatus disconnect_status_for_metrics) {
   if (!callback_) {
     return;
   }
+  if (disconnect_status_for_metrics != FedCmDisconnectStatus::kSuccess) {
+    AddConsoleErrorMessage(disconnect_status_for_metrics);
+  }
 
   std::optional<base::TimeDelta> duration =
       disconnect_request_sent_
@@ -251,4 +254,11 @@
   std::move(callback_).Run(status);
 }
 
+void FederatedAuthDisconnectRequest::AddConsoleErrorMessage(
+    FedCmDisconnectStatus disconnect_status_for_metrics) {
+  render_frame_host_->AddMessageToConsole(
+      blink::mojom::ConsoleMessageLevel::kError,
+      webid::GetDisconnectConsoleErrorMessage(disconnect_status_for_metrics));
+}
+
 }  // namespace content
diff --git a/content/browser/webid/federated_auth_disconnect_request.h b/content/browser/webid/federated_auth_disconnect_request.h
index 3f2633cb..cf5cb81 100644
--- a/content/browser/webid/federated_auth_disconnect_request.h
+++ b/content/browser/webid/federated_auth_disconnect_request.h
@@ -65,6 +65,9 @@
   void Complete(blink::mojom::DisconnectStatus status,
                 content::FedCmDisconnectStatus disconnect_status_for_metrics);
 
+  void AddConsoleErrorMessage(
+      FedCmDisconnectStatus disconnect_status_for_metrics);
+
   std::unique_ptr<IdpNetworkRequestManager> network_manager_;
   // Owned by |BrowserContext|
   raw_ptr<FederatedIdentityPermissionContextDelegate> permission_delegate_ =
diff --git a/content/browser/webid/federated_auth_disconnect_request_unittest.cc b/content/browser/webid/federated_auth_disconnect_request_unittest.cc
index 4070e20..b106cfb 100644
--- a/content/browser/webid/federated_auth_disconnect_request_unittest.cc
+++ b/content/browser/webid/federated_auth_disconnect_request_unittest.cc
@@ -18,6 +18,7 @@
 #include "content/browser/webid/test/mock_api_permission_delegate.h"
 #include "content/browser/webid/test/mock_idp_network_request_manager.h"
 #include "content/browser/webid/test/mock_permission_delegate.h"
+#include "content/browser/webid/webid_utils.h"
 #include "content/public/test/navigation_simulator.h"
 #include "content/test/test_render_view_host.h"
 #include "content/test/test_web_contents.h"
@@ -276,8 +277,8 @@
     EXPECT_EQ(expected_disconnect_status, callback_helper.status());
   }
 
-  void ExpectDisconnectMetrics(DisconnectStatusForMetrics status,
-                               bool should_record_duration) {
+  void ExpectDisconnectMetricsAndConsoleError(DisconnectStatusForMetrics status,
+                                              bool should_record_duration) {
     histogram_tester_.ExpectUniqueSample("Blink.FedCm.Status.Disconnect",
                                          status, 1);
     histogram_tester_.ExpectTotalCount("Blink.FedCm.Timing.Disconnect",
@@ -286,6 +287,15 @@
                         should_record_duration);
     ExpectDisconnectUKM(status, ukm::builders::Blink_FedCmIdp::kEntryName,
                         should_record_duration);
+
+    std::vector<std::string> messages =
+        RenderFrameHostTester::For(main_rfh())->GetConsoleMessages();
+    if (status == DisconnectStatusForMetrics::kSuccess) {
+      EXPECT_TRUE(messages.empty());
+    } else {
+      ASSERT_EQ(messages.size(), 1u);
+      EXPECT_EQ(messages[0], webid::GetDisconnectConsoleErrorMessage(status));
+    }
   }
 
   void ExpectDisconnectUKM(DisconnectStatusForMetrics status,
@@ -352,8 +362,8 @@
   EXPECT_TRUE(network_manager_->has_fetched_config_);
   EXPECT_TRUE(network_manager_->has_fetched_disconnect_);
 
-  ExpectDisconnectMetrics(DisconnectStatusForMetrics::kSuccess,
-                          /*should_record_duration=*/true);
+  ExpectDisconnectMetricsAndConsoleError(DisconnectStatusForMetrics::kSuccess,
+                                         /*should_record_duration=*/true);
 }
 
 TEST_F(FederatedAuthDisconnectRequestTest, NotTrustworthyIdP) {
@@ -362,7 +372,7 @@
   RunDisconnectTest(config, DisconnectStatus::kError);
   EXPECT_FALSE(DidFetchAnyEndpoint());
 
-  ExpectDisconnectMetrics(
+  ExpectDisconnectMetricsAndConsoleError(
       DisconnectStatusForMetrics::kIdpNotPotentiallyTrustworthy,
       /*should_record_duration=*/false);
 }
@@ -389,8 +399,8 @@
   EXPECT_TRUE(network_manager_->has_fetched_config_);
   EXPECT_TRUE(network_manager_->has_fetched_disconnect_);
 
-  ExpectDisconnectMetrics(DisconnectStatusForMetrics::kSuccess,
-                          /*should_record_duration=*/true);
+  ExpectDisconnectMetricsAndConsoleError(DisconnectStatusForMetrics::kSuccess,
+                                         /*should_record_duration=*/true);
 }
 
 }  // namespace content
diff --git a/content/browser/webid/federated_auth_request_impl.cc b/content/browser/webid/federated_auth_request_impl.cc
index fb224688..febb6f6 100644
--- a/content/browser/webid/federated_auth_request_impl.cc
+++ b/content/browser/webid/federated_auth_request_impl.cc
@@ -2817,6 +2817,10 @@
   if (disconnect_request_) {
     // Since we do not send any fetches in this case, consider the request to be
     // instant, e.g. duration is 0.
+    render_frame_host().AddMessageToConsole(
+        blink::mojom::ConsoleMessageLevel::kError,
+        webid::GetDisconnectConsoleErrorMessage(
+            FedCmDisconnectStatus::kTooManyRequests));
     fedcm_metrics_->RecordDisconnectMetrics(
         FedCmDisconnectStatus::kTooManyRequests, std::nullopt);
     std::move(callback).Run(DisconnectStatus::kErrorTooManyRequests);
diff --git a/content/browser/webid/webid_utils.cc b/content/browser/webid/webid_utils.cc
index bdeaebe..94a8ba2 100644
--- a/content/browser/webid/webid_utils.cc
+++ b/content/browser/webid/webid_utils.cc
@@ -25,6 +25,7 @@
 #include "url/origin.h"
 
 using blink::mojom::FederatedAuthRequestResult;
+using content::FedCmDisconnectStatus;
 
 namespace content::webid {
 
@@ -303,6 +304,75 @@
   }
 }
 
+std::string GetDisconnectConsoleErrorMessage(
+    FedCmDisconnectStatus disconnect_status_for_metrics) {
+  switch (disconnect_status_for_metrics) {
+    case FedCmDisconnectStatus::kSuccess: {
+      NOTREACHED();
+      return "";
+    }
+    case FedCmDisconnectStatus::kTooManyRequests: {
+      return "There is a pending disconnect() call.";
+    }
+    case FedCmDisconnectStatus::kUnhandledRequest: {
+      return "The disconnect request did not finish by the time the page was "
+             "closed.";
+    }
+    case FedCmDisconnectStatus::kNoAccountToDisconnect: {
+      return "There is no account to disconnect.";
+    }
+    case FedCmDisconnectStatus::kDisconnectUrlIsCrossOrigin: {
+      return "The disconnect URL is cross origin";
+    }
+    case FedCmDisconnectStatus::kDisconnectFailedOnServer: {
+      return "The disconnect request failed on the server";
+    }
+    case FedCmDisconnectStatus::kConfigHttpNotFound: {
+      return "The config file cannot be found.";
+    }
+    case FedCmDisconnectStatus::kConfigNoResponse: {
+      return "The config file returned an error response code.";
+    }
+    case FedCmDisconnectStatus::kConfigInvalidResponse: {
+      return "The config file returned some invalid response.";
+    }
+    case FedCmDisconnectStatus::kDisabledInSettings: {
+      return "FedCM is disabled by user settings.";
+    }
+    case FedCmDisconnectStatus::kDisabledInFlags: {
+      return "The disconnect API is disabled by a flag.";
+    }
+    case FedCmDisconnectStatus::kWellKnownHttpNotFound: {
+      return "The well known file cannot be found.";
+    }
+    case FedCmDisconnectStatus::kWellKnownNoResponse: {
+      return "The well-known file returned an error response code.";
+    }
+    case FedCmDisconnectStatus::kWellKnownInvalidResponse: {
+      return "The well-known filed returned some invalid response.";
+    }
+    case FedCmDisconnectStatus::kWellKnownListEmpty: {
+      return "The well-known file returned an empty list.";
+    }
+    case FedCmDisconnectStatus::kConfigNotInWellKnown: {
+      return "The config file is not in the well-known file.";
+    }
+    case FedCmDisconnectStatus::kWellKnownTooBig: {
+      return "Provider's FedCM well-known file contains too many config URLs.";
+    }
+    case FedCmDisconnectStatus::kWellKnownInvalidContentType: {
+      return "Provider's well-known content type must be a JSON content type.";
+    }
+    case FedCmDisconnectStatus::kConfigInvalidContentType: {
+      return "Provider's FedCM config file content type must be a JSON content "
+             "type.";
+    }
+    case FedCmDisconnectStatus::kIdpNotPotentiallyTrustworthy: {
+      return "The provider's config file URL is not potentially trustworthy.";
+    }
+  }
+}
+
 FedCmIdpSigninStatusMode GetIdpSigninStatusMode(RenderFrameHost& host,
                                                 const url::Origin& idp_origin) {
   // TODO(crbug.com/1487668): Remove this function in favor of
diff --git a/content/browser/webid/webid_utils.h b/content/browser/webid/webid_utils.h
index 3a4a88e..3df25ac 100644
--- a/content/browser/webid/webid_utils.h
+++ b/content/browser/webid/webid_utils.h
@@ -18,6 +18,7 @@
 
 namespace content {
 class BrowserContext;
+enum class FedCmDisconnectStatus;
 enum class FedCmIdpSigninStatusMode;
 class FedCmMetrics;
 class FederatedIdentityApiPermissionContextDelegate;
@@ -76,6 +77,11 @@
 CONTENT_EXPORT std::string GetConsoleErrorMessageFromResult(
     blink::mojom::FederatedAuthRequestResult result);
 
+// Returns a string to be used as the console error message for a disconnect()
+// call.
+CONTENT_EXPORT std::string GetDisconnectConsoleErrorMessage(
+    FedCmDisconnectStatus disconnect_status_for_metrics);
+
 FedCmIdpSigninStatusMode GetIdpSigninStatusMode(RenderFrameHost& host,
                                                 const url::Origin& idp_origin);
 
diff --git a/content/common/features.cc b/content/common/features.cc
index cef23c62..46fca24 100644
--- a/content/common/features.cc
+++ b/content/common/features.cc
@@ -213,6 +213,12 @@
              "FledgeUseInterestGroupCache",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Enables a delay for the post-auction interest group update to avoid
+// immediately invalidating cached values.
+BASE_FEATURE(kFledgeDelayPostAuctionInterestGroupUpdate,
+             "FledgeDelayPostAuctionInterestGroupUpdate",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // Enables fixes for matching src: local() for web fonts correctly against full
 // font name or postscript name. Rolling out behind a flag, as enabling this
 // enables a font indexer on Android which we need to test in the field first.
@@ -574,11 +580,6 @@
              "WebOTPAssertionFeaturePolicy",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// Flag guard for fix for crbug.com/1414936.
-BASE_FEATURE(kWindowOpenFileSelectFix,
-             "WindowOpenFileSelectFix",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 // Please keep features in alphabetical order.
 
 }  // namespace features
diff --git a/content/common/features.h b/content/common/features.h
index c6e86f7..4fdfe67d 100644
--- a/content/common/features.h
+++ b/content/common/features.h
@@ -47,6 +47,7 @@
 CONTENT_EXPORT extern const base::FeatureParam<int>
     kFledgeLimitNumAuctionsParam;
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kFledgeUseInterestGroupCache);
+CONTENT_EXPORT BASE_DECLARE_FEATURE(kFledgeDelayPostAuctionInterestGroupUpdate);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kFontSrcLocalMatching);
 #if !BUILDFLAG(IS_ANDROID)
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kForwardMemoryPressureEventsToGpuProcess);
@@ -122,7 +123,6 @@
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kWebGLImageChromium);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kWebOTPAssertionFeaturePolicy);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kWebRtcUseGpuMemoryBufferVideoFrames);
-CONTENT_EXPORT BASE_DECLARE_FEATURE(kWindowOpenFileSelectFix);
 
 // Please keep features in alphabetical order.
 
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn
index 7096c8f..d515ac3 100644
--- a/content/public/android/BUILD.gn
+++ b/content/public/android/BUILD.gn
@@ -261,7 +261,6 @@
     "java/src/org/chromium/content/browser/accessibility/AccessibilityNodeInfoBuilder.java",
     "java/src/org/chromium/content/browser/accessibility/AccessibilityNodeInfoUtils.java",
     "java/src/org/chromium/content/browser/accessibility/AutoDisableAccessibilityHandler.java",
-    "java/src/org/chromium/content/browser/accessibility/OViewStructureBuilder.java",
     "java/src/org/chromium/content/browser/accessibility/ViewStructureBuilder.java",
     "java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityDelegate.java",
     "java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java",
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/AccessibilityNodeInfoBuilder.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/AccessibilityNodeInfoBuilder.java
index a86c20b..731b03bb 100644
--- a/content/public/android/java/src/org/chromium/content/browser/accessibility/AccessibilityNodeInfoBuilder.java
+++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/AccessibilityNodeInfoBuilder.java
@@ -44,7 +44,6 @@
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.graphics.Rect;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.text.SpannableString;
@@ -52,7 +51,6 @@
 import android.text.style.SuggestionSpan;
 import android.text.style.URLSpan;
 import android.view.View;
-import android.view.accessibility.AccessibilityNodeInfo;
 
 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
 
@@ -189,7 +187,8 @@
             boolean password,
             boolean scrollable,
             boolean selected,
-            boolean visibleToUser) {
+            boolean visibleToUser,
+            boolean hasCharacterLocations) {
         node.setCheckable(checkable);
         node.setChecked(checked);
         node.setClickable(clickable);
@@ -228,6 +227,11 @@
         if (hasImage) {
             Bundle bundle = node.getExtras();
             bundle.putCharSequence(EXTRAS_KEY_HAS_IMAGE, "true");
+            node.setAvailableExtraData(sRequestImageData);
+        }
+
+        if (hasCharacterLocations) {
+            node.setAvailableExtraData(sTextCharacterLocation);
         }
 
         node.setMovementGranularities(
@@ -381,6 +385,7 @@
         }
         bundle.putCharSequence(EXTRAS_KEY_CHROME_ROLE, role);
         bundle.putCharSequence(EXTRAS_KEY_ROLE_DESCRIPTION, roleDescription);
+        // We added the hint Bundle extra pre Android-O, and keep it to not risk breaking changes.
         bundle.putCharSequence(EXTRAS_KEY_HINT, hint);
         if (!display.isEmpty()) {
             bundle.putCharSequence(EXTRAS_KEY_CSS_DISPLAY, display);
@@ -400,6 +405,7 @@
         node.setDismissable(false); // No concept of "dismissable" on the web currently.
         node.setMultiLine(multiLine);
         node.setInputType(inputType);
+        node.setHintText(hint);
 
         // Deliberately don't call setLiveRegion because TalkBack speaks
         // the entire region anytime it changes. Instead Chrome will
@@ -534,27 +540,6 @@
     }
 
     @CalledByNative
-    protected void setAccessibilityNodeInfoOAttributes(
-            AccessibilityNodeInfoCompat node,
-            boolean hasCharacterLocations,
-            boolean hasImage,
-            String hint) {
-        node.setHintText(hint);
-
-        // Work-around a gap in the Android API, that |AccessibilityNodeInfoCompat| class does not
-        // have the setAvailableExtraData method, so unwrap the node and call it directly.
-        // TODO(mschillaci): Remove unwrapping and SDK version req once Android API is updated.
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-            if (hasCharacterLocations) {
-                ((AccessibilityNodeInfo) node.getInfo())
-                        .setAvailableExtraData(sTextCharacterLocation);
-            } else if (hasImage) {
-                ((AccessibilityNodeInfo) node.getInfo()).setAvailableExtraData(sRequestImageData);
-            }
-        }
-    }
-
-    @CalledByNative
     protected void setAccessibilityNodeInfoPaneTitle(
             AccessibilityNodeInfoCompat node, String title) {
         node.setPaneTitle(title);
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/OViewStructureBuilder.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/OViewStructureBuilder.java
deleted file mode 100644
index 4f97462..0000000
--- a/content/public/android/java/src/org/chromium/content/browser/accessibility/OViewStructureBuilder.java
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.content.browser.accessibility;
-
-import android.os.Build;
-import android.view.ViewStructure;
-
-import androidx.annotation.RequiresApi;
-
-import org.chromium.content.browser.RenderCoordinatesImpl;
-
-/**
- */
-public class OViewStructureBuilder extends ViewStructureBuilder {
-    public OViewStructureBuilder(RenderCoordinatesImpl renderCoordinates) {
-        super(renderCoordinates);
-    }
-
-    @RequiresApi(Build.VERSION_CODES.O)
-    @Override
-    protected void setViewStructureNodeHtmlInfo(
-            ViewStructure node, String htmlTag, String cssDisplay, String[][] htmlAttributes) {
-        super.setViewStructureNodeHtmlInfo(node, htmlTag, cssDisplay, htmlAttributes);
-
-        ViewStructure.HtmlInfo.Builder htmlBuilder = node.newHtmlInfoBuilder(htmlTag);
-        if (htmlBuilder != null) {
-            htmlBuilder.addAttribute("display", cssDisplay);
-            for (String[] attr : htmlAttributes) {
-                htmlBuilder.addAttribute(attr[0], attr[1]);
-            }
-            node.setHtmlInfo(htmlBuilder.build());
-        }
-    }
-}
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/ViewStructureBuilder.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/ViewStructureBuilder.java
index e820cfc2..c34305a 100644
--- a/content/public/android/java/src/org/chromium/content/browser/accessibility/ViewStructureBuilder.java
+++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/ViewStructureBuilder.java
@@ -15,7 +15,6 @@
 
 import android.app.assist.AssistStructure.ViewNode;
 import android.graphics.Rect;
-import android.os.Build;
 import android.os.Bundle;
 import android.view.ViewStructure;
 
@@ -31,14 +30,7 @@
 public class ViewStructureBuilder {
     private RenderCoordinatesImpl mRenderCoordinates;
 
-    public static ViewStructureBuilder create(RenderCoordinatesImpl renderCoordinates) {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-            return new OViewStructureBuilder(renderCoordinates);
-        }
-        return new ViewStructureBuilder(renderCoordinates);
-    }
-
-    protected ViewStructureBuilder(RenderCoordinatesImpl renderCoordinates) {
+    public ViewStructureBuilder(RenderCoordinatesImpl renderCoordinates) {
         this.mRenderCoordinates = renderCoordinates;
     }
 
@@ -122,11 +114,13 @@
     @CalledByNative
     protected void setViewStructureNodeHtmlInfo(
             ViewStructure node, String htmlTag, String cssDisplay, String[][] htmlAttributes) {
-        Bundle extras = node.getExtras();
-        extras.putCharSequence("htmlTag", htmlTag);
-        extras.putCharSequence("display", cssDisplay);
-        for (String[] attr : htmlAttributes) {
-            extras.putCharSequence(attr[0], attr[1]);
+        ViewStructure.HtmlInfo.Builder htmlBuilder = node.newHtmlInfoBuilder(htmlTag);
+        if (htmlBuilder != null) {
+            htmlBuilder.addAttribute("display", cssDisplay);
+            for (String[] attr : htmlAttributes) {
+                htmlBuilder.addAttribute(attr[0], attr[1]);
+            }
+            node.setHtmlInfo(htmlBuilder.build());
         }
     }
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
index 0072c69b..c8e89e99 100644
--- a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
@@ -831,7 +831,7 @@
      */
     public void requestAccessibilitySnapshot(ViewStructure root, Runnable doneCallback) {
         checkNotDestroyed();
-        ViewStructureBuilder builder = ViewStructureBuilder.create(mRenderCoordinates);
+        ViewStructureBuilder builder = new ViewStructureBuilder(mRenderCoordinates);
 
         WebContentsImplJni.get()
                 .requestAccessibilitySnapshot(
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/TestViewStructure.java b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/TestViewStructure.java
index f0562c9..44fb9a8 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/TestViewStructure.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/TestViewStructure.java
@@ -24,6 +24,8 @@
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillValue;
 
+import androidx.annotation.NonNull;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -108,7 +110,9 @@
         }
         builder.append(TextUtils.join(", ", bundleStrings)).append("]");
 
-        return builder.toString();
+        // If all keys were filtered, return an empty string.
+        String ret = builder.toString();
+        return ret.equals("[]") ? "" : ret;
     }
 
     private void recursiveDumpToString(StringBuilder builder, int indent) {
@@ -144,7 +148,7 @@
         }
 
         // Print font styling values.
-        builder.append(" textSize:").append(String.format("%.2f", mTextSize));
+        builder.append(" textSize:").append(String.format("%.1f", mTextSize));
         builder.append(" style:").append(mStyle);
         if (mFgColor != 0xFF000000) {
             builder.append(" fgColor:").append(mFgColor);
@@ -155,18 +159,23 @@
 
         // Print Bundle extras and htmlInfo attributes.
         if (mBundle != null) {
-            builder.append(" bundle:").append(bundleToString(mBundle));
+            String bundleString = bundleToString(mBundle);
+            if (!bundleString.isEmpty()) {
+                builder.append(" bundle:").append(bundleString);
+            }
         }
         if (mHtmlInfo != null) {
             builder.append(" htmlInfo:[");
+            List<String> attrStrings = new ArrayList<>();
+            attrStrings.add("{htmlTag=\"" + mHtmlInfo.getTag() + "\"}");
             for (Pair<String, String> pair : mHtmlInfo.getAttributes()) {
                 // We add an extra html attribute for debugging, do not print these values in tests.
                 if (pair.first.equals("root_scroll_y")) {
                     continue;
                 }
-                builder.append(" {").append(pair.first).append(",").append(pair.second).append("}");
+                attrStrings.add("{" + pair.first + "=\"" + pair.second + "\"}");
             }
-            builder.append(" ]");
+            builder.append(TextUtils.join(", ", attrStrings)).append("]");
         }
 
         builder.append("\n");
@@ -283,7 +292,7 @@
 
     @Override
     public HtmlInfo.Builder newHtmlInfoBuilder(String tag) {
-        return null;
+        return new TestBuilder(tag);
     }
 
     @Override
@@ -393,4 +402,48 @@
 
     @Override
     public void setWebDomain(String webDomain) {}
+
+    /** Test implementation of {@link HtmlInfo}. */
+    public static class TestHtmlInfo extends HtmlInfo {
+        private final String mTag;
+        private final List<Pair<String, String>> mAttributes;
+
+        public TestHtmlInfo(String tag, List<Pair<String, String>> attributes) {
+            mTag = tag;
+            mAttributes = attributes;
+        }
+
+        @Override
+        public List<Pair<String, String>> getAttributes() {
+            return mAttributes;
+        }
+
+        @NonNull
+        @Override
+        public String getTag() {
+            return mTag;
+        }
+    }
+
+    /** Test implementation of {@link HtmlInfo.Builder}. */
+    public static class TestBuilder extends HtmlInfo.Builder {
+        private final String mTag;
+        private final List<Pair<String, String>> mAttributes;
+
+        public TestBuilder(String tag) {
+            mTag = tag;
+            mAttributes = new ArrayList<Pair<String, String>>();
+        }
+
+        @Override
+        public HtmlInfo.Builder addAttribute(@NonNull String name, @NonNull String value) {
+            mAttributes.add(new Pair<String, String>(name, value));
+            return this;
+        }
+
+        @Override
+        public HtmlInfo build() {
+            return new TestHtmlInfo(mTag, mAttributes);
+        }
+    }
 }
diff --git a/content/test/data/accessibility/accname/desc-combobox-focusable-expected-android-assist-data.txt b/content/test/data/accessibility/accname/desc-combobox-focusable-expected-android-assist-data.txt
index e60290dd..281bf995 100644
--- a/content/test/data/accessibility/accname/desc-combobox-focusable-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/accname/desc-combobox-focusable-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++Spinner text:"English" textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="test", role="combobox", tabindex="0", title="Choose your language."]
-++++TextView text:"English" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++Spinner text:"English" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="test"}, {role="combobox"}, {tabindex="0"}, {title="Choose your language."}]
+++++TextView text:"English" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/accname/desc-from-content-of-describedby-element-expected-android-assist-data.txt b/content/test/data/accessibility/accname/desc-from-content-of-describedby-element-expected-android-assist-data.txt
index 01deae1..a5dce88 100644
--- a/content/test/data/accessibility/accname/desc-from-content-of-describedby-element-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/accname/desc-from-content-of-describedby-element-expected-android-assist-data.txt
@@ -1,19 +1,19 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++EditText text:"Important stuff My name is Eli the weird. (QED) Where are my marbles?" textSize:13.33 style:0 bundle:[aria-describedby="descId", aria-label="Important stuff", display="inline-block", htmlTag="input", id="test", type="text"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="descId"]
-++++TextView text:"My" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" name is" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++View text:"Eli" textSize:16.00 style:0 bundle:[aria-label="Eli", display="inline", htmlTag="span", role="presentation"]
-++++++View text:"Garaventa" textSize:16.00 style:0 bundle:[aria-label="Garaventa", display="inline", htmlTag="span"]
-++++++++TextView text:"Zambino" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"the weird." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" (QED)" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table", htmlTag="table"]
-++++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++++TextView text:"Where" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++++TextView text:"are my marbles?" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++EditText text:"Important stuff My name is Eli the weird. (QED) Where are my marbles?" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-describedby="descId"}, {aria-label="Important stuff"}, {id="test"}, {type="text"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="descId"}]
+++++TextView text:"My" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" name is" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++View text:"Eli" textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-label="Eli"}, {role="presentation"}]
+++++++View text:"Garaventa" textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-label="Garaventa"}]
+++++++++TextView text:"Zambino" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"the weird." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" (QED)" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++++TextView text:"Where" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++++TextView text:"are my marbles?" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/accname/name-combobox-focusable-expected-android-assist-data.txt b/content/test/data/accessibility/accname/name-combobox-focusable-expected-android-assist-data.txt
index e60290dd..281bf995 100644
--- a/content/test/data/accessibility/accname/name-combobox-focusable-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/accname/name-combobox-focusable-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++Spinner text:"English" textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="test", role="combobox", tabindex="0", title="Choose your language."]
-++++TextView text:"English" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++Spinner text:"English" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="test"}, {role="combobox"}, {tabindex="0"}, {title="Choose your language."}]
+++++TextView text:"English" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/accname/name-div-content-only-expected-android-assist-data.txt b/content/test/data/accessibility/accname/name-div-content-only-expected-android-assist-data.txt
index 02b85fc6a..d3d01ce 100644
--- a/content/test/data/accessibility/accname/name-div-content-only-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/accname/name-div-content-only-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="test"]
-++++TextView text:"Div with text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="test"}]
+++++TextView text:"Div with text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/annotation-roles-expected-android-assist-data.txt b/content/test/data/accessibility/aria/annotation-roles-expected-android-assist-data.txt
index b710e52..9db6b5f 100644
--- a/content/test/data/accessibility/aria/annotation-roles-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/annotation-roles-expected-android-assist-data.txt
@@ -1,8 +1,8 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View text:"comment" textSize:16.00 style:0 bundle:[aria-label="comment", display="block", htmlTag="div", role="comment"]
-++View text:"suggestion" textSize:16.00 style:0 bundle:[aria-label="suggestion", display="block", htmlTag="div", role="suggestion"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"This is " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="mark"]
-++++++TextView text:"highlighted" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View text:"comment" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="comment"}, {role="comment"}]
+++View text:"suggestion" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="suggestion"}, {role="suggestion"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"This is " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="mark"}]
+++++++TextView text:"highlighted" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-alert-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-alert-expected-android-assist-data.txt
index d5f120c..f1fea686 100644
--- a/content/test/data/accessibility/aria/aria-alert-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-alert-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p", id="ariaalert", role="alert"]
-++++TextView text:"This test is for aria role="alert"" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {id="ariaalert"}, {role="alert"}]
+++++TextView text:"This test is for aria role="alert"" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-alertdialog-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-alertdialog-expected-android-assist-data.txt
index 4045aa8..382b3eb4 100644
--- a/content/test/data/accessibility/aria/aria-alertdialog-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-alertdialog-expected-android-assist-data.txt
@@ -1,2 +1,2 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="alertdialog"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="alertdialog"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-application-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-application-expected-android-assist-data.txt
index 460674a1..c2d5325 100644
--- a/content/test/data/accessibility/aria/aria-application-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-application-expected-android-assist-data.txt
@@ -1,2 +1,2 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body", id="testAriaApplication", role="application"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}, {id="testAriaApplication"}, {role="application"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-article-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-article-expected-android-assist-data.txt
index 5397e2c..a96ca40 100644
--- a/content/test/data/accessibility/aria/aria-article-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-article-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="article"]
-++++TextView text:"This is an ARIA article." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="article"}]
+++++TextView text:"This is an ARIA article." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-atomic-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-atomic-expected-android-assist-data.txt
index c2ffc835..88c719cb 100644
--- a/content/test/data/accessibility/aria/aria-atomic-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-atomic-expected-android-assist-data.txt
@@ -1,9 +1,9 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[aria-atomic="false", aria-live="polite", display="block", htmlTag="p", id="ariaatomicfalse", role="log", tabindex="0"]
-++++TextView text:"This test is for aria-atomic="false"" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-atomic="true", aria-live="polite", display="block", htmlTag="p", id="ariaatomictrue", role="log", tabindex="1"]
-++++TextView text:"This test is for aria-atomic="true"" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p", id="alert", role="alert", tabindex="2"]
-++++TextView text:"This test is for alert." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p", id="status", role="status", tabindex="3"]
-++++TextView text:"This test is for status." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {aria-atomic="false"}, {aria-live="polite"}, {id="ariaatomicfalse"}, {role="log"}, {tabindex="0"}]
+++++TextView text:"This test is for aria-atomic="false"" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {aria-atomic="true"}, {aria-live="polite"}, {id="ariaatomictrue"}, {role="log"}, {tabindex="1"}]
+++++TextView text:"This test is for aria-atomic="true"" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {id="alert"}, {role="alert"}, {tabindex="2"}]
+++++TextView text:"This test is for alert." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {id="status"}, {role="status"}, {tabindex="3"}]
+++++TextView text:"This test is for status." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-autocomplete-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-autocomplete-expected-android-assist-data.txt
index 02ec62d9..7273888 100644
--- a/content/test/data/accessibility/aria/aria-autocomplete-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-autocomplete-expected-android-assist-data.txt
@@ -1,17 +1,17 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++EditText text:"autocomplete=inline" textSize:13.33 style:0 bundle:[aria-autocomplete="inline", display="inline-block", htmlTag="input", role="combobox", value="autocomplete=inline"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++++++TextView text:"autocomplete=inline" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++++EditText text:"autocomplete=list" textSize:13.33 style:0 bundle:[aria-autocomplete="list", display="inline-block", htmlTag="input", role="combobox", value="autocomplete=list"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++++++TextView text:"autocomplete=list" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++++EditText text:"autocomplete=both" textSize:13.33 style:0 bundle:[aria-autocomplete="both", display="inline-block", htmlTag="input", role="combobox", value="autocomplete=both"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++++++TextView text:"autocomplete=both" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++++EditText text:"autocomplete=none" textSize:13.33 style:0 bundle:[aria-autocomplete="none", display="inline-block", htmlTag="input", role="combobox", value="autocomplete=none"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++++++TextView text:"autocomplete=none" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++++EditText text:"No role with autocomplete=inline" textSize:13.33 style:0 bundle:[aria-autocomplete="inline", display="inline-block", htmlTag="input", type="text", value="No role with autocomplete=inline"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++++++TextView text:"No role with autocomplete=inline" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++EditText text:"autocomplete=inline" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-autocomplete="inline"}, {role="combobox"}, {value="autocomplete=inline"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++++++TextView text:"autocomplete=inline" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++EditText text:"autocomplete=list" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-autocomplete="list"}, {role="combobox"}, {value="autocomplete=list"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++++++TextView text:"autocomplete=list" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++EditText text:"autocomplete=both" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-autocomplete="both"}, {role="combobox"}, {value="autocomplete=both"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++++++TextView text:"autocomplete=both" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++EditText text:"autocomplete=none" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-autocomplete="none"}, {role="combobox"}, {value="autocomplete=none"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++++++TextView text:"autocomplete=none" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++EditText text:"No role with autocomplete=inline" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-autocomplete="inline"}, {type="text"}, {value="No role with autocomplete=inline"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++++++TextView text:"No role with autocomplete=inline" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-banner-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-banner-expected-android-assist-data.txt
index 12b111a5..64baa4f 100644
--- a/content/test/data/accessibility/aria/aria-banner-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-banner-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="banner"]
-++++TextView text:"Chromium Browser" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="banner"}]
+++++TextView text:"Chromium Browser" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-braillelabel-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-braillelabel-expected-android-assist-data.txt
index 107131d49..7f03c30 100644
--- a/content/test/data/accessibility/aria/aria-braillelabel-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-braillelabel-expected-android-assist-data.txt
@@ -1,2 +1,2 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++CheckBox textSize:16.00 style:0 bundle:[aria-braillelabel="aria braille label", display="block", htmlTag="div", role="checkbox"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++CheckBox textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-braillelabel="aria braille label"}, {role="checkbox"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-brailleroledescription-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-brailleroledescription-expected-android-assist-data.txt
index 427a1408..39330cd 100644
--- a/content/test/data/accessibility/aria/aria-brailleroledescription-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-brailleroledescription-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++CheckBox textSize:16.00 style:0 bundle:[aria-brailleroledescription="aria braille role description", display="block", htmlTag="div", role="checkbox"]
-++CheckBox textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="checkbox"]
-++CheckBox textSize:16.00 style:0 bundle:[aria-brailleroledescription="", display="block", htmlTag="div", role="checkbox"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++CheckBox textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-brailleroledescription="aria braille role description"}, {role="checkbox"}]
+++CheckBox textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="checkbox"}]
+++CheckBox textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-brailleroledescription=""}, {role="checkbox"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-busy-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-busy-expected-android-assist-data.txt
index daa8a8c8..76bc5cd3 100644
--- a/content/test/data/accessibility/aria/aria-busy-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-busy-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View text:"Busy log" textSize:16.00 style:0 bundle:[aria-busy="true", aria-label="Busy log", display="block", htmlTag="div", role="log", tabindex="0"]
-++View text:"Not-busy log" textSize:16.00 style:0 bundle:[aria-busy="false", aria-label="Not-busy log", display="block", htmlTag="div", role="log", tabindex="1"]
-++View text:"plain div" textSize:16.00 style:0 bundle:[aria-busy="true", aria-description="plain div", display="block", htmlTag="div", name="plain div"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View text:"Busy log" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-busy="true"}, {aria-label="Busy log"}, {role="log"}, {tabindex="0"}]
+++View text:"Not-busy log" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-busy="false"}, {aria-label="Not-busy log"}, {role="log"}, {tabindex="1"}]
+++View text:"plain div" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-busy="true"}, {aria-description="plain div"}, {name="plain div"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-button-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-button-expected-android-assist-data.txt
index 478f6cc..0bda2e9 100644
--- a/content/test/data/accessibility/aria/aria-button-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-button-expected-android-assist-data.txt
@@ -1,39 +1,39 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++Button textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="button", tabindex="0"]
-++++TextView text:"Button1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ToggleButton textSize:16.00 style:0 bundle:[aria-pressed="true", display="block", htmlTag="div", role="button", tabindex="1"]
-++++TextView text:"Button2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ToggleButton textSize:16.00 style:0 bundle:[aria-pressed="false", display="block", htmlTag="div", role="button", tabindex="2"]
-++++TextView text:"Button3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++Button textSize:16.00 style:0 bundle:[aria-haspopup="true", display="block", htmlTag="div", role="button", tabindex="3"]
-++++TextView text:"Button4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++Button textSize:16.00 style:0 bundle:[aria-haspopup="false", display="block", htmlTag="div", role="button", tabindex="4"]
-++++TextView text:"Button5" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++Button textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="button", tabindex="5"]
-++++TextView text:"Complex button " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++EditText textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++ToggleButton textSize:16.00 style:0 bundle:[aria-pressed="true", display="block", htmlTag="div", role="button", tabindex="6"]
-++++TextView text:"Complex toggle button " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++EditText textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++Button textSize:16.00 style:0 bundle:[aria-haspopup="true", display="block", htmlTag="div", role="button", tabindex="7"]
-++++TextView text:"Complex pop up button " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++EditText textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++Button textSize:16.00 style:0 bundle:[aria-haspopup="true", display="block", htmlTag="div", role="button"]
-++++TextView text:"Example haspopup" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++Button textSize:16.00 style:0 bundle:[aria-haspopup="menu", display="block", htmlTag="div", role="button"]
-++++TextView text:"Example haspopup" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++Button textSize:16.00 style:0 bundle:[aria-haspopup="listbox", display="block", htmlTag="div", role="button"]
-++++TextView text:"Example haspopup" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++Button textSize:16.00 style:0 bundle:[aria-haspopup="tree", display="block", htmlTag="div", role="button"]
-++++TextView text:"Example haspopup" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++Button textSize:16.00 style:0 bundle:[aria-haspopup="grid", display="block", htmlTag="div", role="button"]
-++++TextView text:"Example haspopup" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++Button textSize:16.00 style:0 bundle:[aria-haspopup="dialog", display="block", htmlTag="div", role="button"]
-++++TextView text:"Example haspopup" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++Button textSize:16.00 style:0 bundle:[aria-haspopup="false", display="block", htmlTag="div", role="button"]
-++++TextView text:"Example haspopup" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++Button textSize:16.00 style:0 bundle:[aria-haspopup="bad_input", display="block", htmlTag="div", role="button"]
-++++TextView text:"Example haspopup" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++Button textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="button"}, {tabindex="0"}]
+++++TextView text:"Button1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ToggleButton textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-pressed="true"}, {role="button"}, {tabindex="1"}]
+++++TextView text:"Button2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ToggleButton textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-pressed="false"}, {role="button"}, {tabindex="2"}]
+++++TextView text:"Button3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-haspopup="true"}, {role="button"}, {tabindex="3"}]
+++++TextView text:"Button4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-haspopup="false"}, {role="button"}, {tabindex="4"}]
+++++TextView text:"Button5" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="button"}, {tabindex="5"}]
+++++TextView text:"Complex button " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++ToggleButton textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-pressed="true"}, {role="button"}, {tabindex="6"}]
+++++TextView text:"Complex toggle button " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++Button textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-haspopup="true"}, {role="button"}, {tabindex="7"}]
+++++TextView text:"Complex pop up button " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++Button textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-haspopup="true"}, {role="button"}]
+++++TextView text:"Example haspopup" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-haspopup="menu"}, {role="button"}]
+++++TextView text:"Example haspopup" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-haspopup="listbox"}, {role="button"}]
+++++TextView text:"Example haspopup" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-haspopup="tree"}, {role="button"}]
+++++TextView text:"Example haspopup" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-haspopup="grid"}, {role="button"}]
+++++TextView text:"Example haspopup" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-haspopup="dialog"}, {role="button"}]
+++++TextView text:"Example haspopup" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-haspopup="false"}, {role="button"}]
+++++TextView text:"Example haspopup" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-haspopup="bad_input"}, {role="button"}]
+++++TextView text:"Example haspopup" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-cell-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-cell-expected-android-assist-data.txt
index 6292ee03..898d563 100644
--- a/content/test/data/accessibility/aria/aria-cell-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-cell-expected-android-assist-data.txt
@@ -1,12 +1,12 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++GridView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="table"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="columnheader"]
-++++++++TextView text:"Browser" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="columnheader"]
-++++++++TextView text:"Rendering Engine" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="cell"]
-++++++++TextView text:"Chrome" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="cell"]
-++++++++TextView text:"Blink" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="table"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="columnheader"}]
+++++++++TextView text:"Browser" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="columnheader"}]
+++++++++TextView text:"Rendering Engine" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="cell"}]
+++++++++TextView text:"Chrome" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="cell"}]
+++++++++TextView text:"Blink" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-checkbox-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-checkbox-expected-android-assist-data.txt
index 4ff37f9c..ceabef8 100644
--- a/content/test/data/accessibility/aria/aria-checkbox-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-checkbox-expected-android-assist-data.txt
@@ -1,14 +1,14 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++CheckBox textSize:16.00 style:0 bundle:[aria-checked="true", display="block", htmlTag="div", role="checkbox", tabindex="0"]
-++++TextView text:"CheckBox1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++CheckBox textSize:16.00 style:0 bundle:[aria-checked="false", display="block", htmlTag="div", role="checkbox", tabindex="1"]
-++++TextView text:"CheckBox2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++CheckBox textSize:16.00 style:0 bundle:[aria-checked="mixed", display="block", htmlTag="div", role="checkbox", tabindex="2"]
-++++TextView text:"CheckBox3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++CheckBox textSize:16.00 style:0 bundle:[aria-checked="undefined", display="block", htmlTag="div", role="checkbox", tabindex="3"]
-++++TextView text:"CheckBox4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++CheckBox textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="checkbox", tabindex="4"]
-++++TextView text:"Complex " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++EditText textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++TextView text:" checkbox" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++CheckBox textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-checked="true"}, {role="checkbox"}, {tabindex="0"}]
+++++TextView text:"CheckBox1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++CheckBox textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-checked="false"}, {role="checkbox"}, {tabindex="1"}]
+++++TextView text:"CheckBox2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++CheckBox textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-checked="mixed"}, {role="checkbox"}, {tabindex="2"}]
+++++TextView text:"CheckBox3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++CheckBox textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-checked="undefined"}, {role="checkbox"}, {tabindex="3"}]
+++++TextView text:"CheckBox4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++CheckBox textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="checkbox"}, {tabindex="4"}]
+++++TextView text:"Complex " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++TextView text:" checkbox" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-checked-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-checked-expected-android-assist-data.txt
index fbdb61c..f2ae572 100644
--- a/content/test/data/accessibility/aria/aria-checked-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-checked-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++CheckBox textSize:16.00 style:0 bundle:[aria-checked="true", display="block", htmlTag="div", role="checkbox", tabindex="0"]
-++CheckBox textSize:16.00 style:0 bundle:[aria-checked="false", display="block", htmlTag="div", role="checkbox", tabindex="1"]
-++CheckBox textSize:16.00 style:0 bundle:[aria-checked="mixed", display="block", htmlTag="div", role="checkbox", tabindex="2"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++CheckBox textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-checked="true"}, {role="checkbox"}, {tabindex="0"}]
+++CheckBox textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-checked="false"}, {role="checkbox"}, {tabindex="1"}]
+++CheckBox textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-checked="mixed"}, {role="checkbox"}, {tabindex="2"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-code-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-code-expected-android-assist-data.txt
index baac943..141efdb 100644
--- a/content/test/data/accessibility/aria/aria-code-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-code-expected-android-assist-data.txt
@@ -1,7 +1,7 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="code"]
-++++TextView text:"role" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++TextView text:"element (no name)" textSize:13.00 style:0 bundle:[display="", htmlTag=""]
-++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"include me" textSize:13.00 style:0 bundle:[aria-label="include me", display="inline", htmlTag="code"]
-++++TextView text:"element (with name)" textSize:13.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="code"}]
+++++TextView text:"role" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++TextView text:"element (no name)" textSize:13.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"include me" textSize:13.0 style:0 htmlInfo:[{htmlTag="code"}, {display="inline"}, {aria-label="include me"}]
+++++TextView text:"element (with name)" textSize:13.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-col-attr-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-col-attr-expected-android-assist-data.txt
index 50509062..c4e80ff 100644
--- a/content/test/data/accessibility/aria/aria-col-attr-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-col-attr-expected-android-assist-data.txt
@@ -1,18 +1,18 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++GridView textSize:16.00 style:0 bundle:[aria-colcount="5", display="block", htmlTag="div", role="grid"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[aria-colindex="2", aria-colspan="2", display="inline", htmlTag="span", role="columnheader"]
-++++++++TextView text:"cell 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[aria-colindex="4", display="inline", htmlTag="span", role="columnheader"]
-++++++++TextView text:"cell 4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[aria-colindex="5", display="inline", htmlTag="span", role="columnheader"]
-++++++++TextView text:"cell 5" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-colindex="2", display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"cell 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"cell 3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"cell 4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"cell 5" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-colcount="5"}, {role="grid"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="2"}, {aria-colspan="2"}, {role="columnheader"}]
+++++++++TextView text:"cell 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="4"}, {role="columnheader"}]
+++++++++TextView text:"cell 4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="5"}, {role="columnheader"}]
+++++++++TextView text:"cell 5" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-colindex="2"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"cell 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"cell 3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"cell 4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"cell 5" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-col-row-index-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-col-row-index-expected-android-assist-data.txt
index 296c759..1e18f00 100644
--- a/content/test/data/accessibility/aria/aria-col-row-index-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-col-row-index-expected-android-assist-data.txt
@@ -1,49 +1,49 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++GridView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="table"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="rowgroup"]
-++++++View textSize:16.00 style:0 bundle:[aria-rowindex="2", display="block", htmlTag="div", role="row"]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="2", display="inline", htmlTag="span", role="columnheader"]
-++++++++++TextView text:"row2 colheader2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="3", display="inline", htmlTag="span", role="columnheader"]
-++++++++++TextView text:"row2 colheader3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="4", display="inline", htmlTag="span", role="columnheader"]
-++++++++++TextView text:"row2 colheader4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="5", display="inline", htmlTag="span", role="columnheader"]
-++++++++++TextView text:"row2 colheader5" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="rowgroup"]
-++++++View textSize:16.00 style:0 bundle:[aria-rowindex="3", display="block", htmlTag="div", role="row"]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="2", display="inline", htmlTag="span", role="cell"]
-++++++++++TextView text:"row3 col2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="3", display="inline", htmlTag="span", role="cell"]
-++++++++++TextView text:"row3 col3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="4", display="inline", htmlTag="span", role="cell"]
-++++++++++TextView text:"row3 col4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="5", display="inline", htmlTag="span", role="cell"]
-++++++++++TextView text:"row3 col5" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[aria-rowindex="4", display="block", htmlTag="div", role="row"]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="2", display="inline", htmlTag="span", role="cell"]
-++++++++++TextView text:"row4 col2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="3", display="inline", htmlTag="span", role="cell"]
-++++++++++TextView text:"row4 col3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="4", display="inline", htmlTag="span", role="cell"]
-++++++++++TextView text:"row4 col4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="5", display="inline", htmlTag="span", role="cell"]
-++++++++++TextView text:"row4 col5" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[aria-rowindex="5", display="block", htmlTag="div", role="row"]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="2", display="inline", htmlTag="span", role="cell"]
-++++++++++TextView text:"row5 col2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="3", display="inline", htmlTag="span", role="cell"]
-++++++++++TextView text:"row5 col3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="4", display="inline", htmlTag="span", role="cell"]
-++++++++++TextView text:"row5 col4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="5", display="inline", htmlTag="span", role="cell"]
-++++++++++TextView text:"row5 col5" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[aria-rowindex="6", display="block", htmlTag="div", role="row"]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="2", display="inline", htmlTag="span", role="cell"]
-++++++++++TextView text:"row6 col2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="3", display="inline", htmlTag="span", role="cell"]
-++++++++++TextView text:"row6 col3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="4", display="inline", htmlTag="span", role="cell"]
-++++++++++TextView text:"row6 col4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="5", display="inline", htmlTag="span", role="cell"]
-++++++++++TextView text:"row6 col5" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="table"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="rowgroup"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-rowindex="2"}, {role="row"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="2"}, {role="columnheader"}]
+++++++++++TextView text:"row2 colheader2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="3"}, {role="columnheader"}]
+++++++++++TextView text:"row2 colheader3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="4"}, {role="columnheader"}]
+++++++++++TextView text:"row2 colheader4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="5"}, {role="columnheader"}]
+++++++++++TextView text:"row2 colheader5" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="rowgroup"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-rowindex="3"}, {role="row"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="2"}, {role="cell"}]
+++++++++++TextView text:"row3 col2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="3"}, {role="cell"}]
+++++++++++TextView text:"row3 col3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="4"}, {role="cell"}]
+++++++++++TextView text:"row3 col4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="5"}, {role="cell"}]
+++++++++++TextView text:"row3 col5" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-rowindex="4"}, {role="row"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="2"}, {role="cell"}]
+++++++++++TextView text:"row4 col2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="3"}, {role="cell"}]
+++++++++++TextView text:"row4 col3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="4"}, {role="cell"}]
+++++++++++TextView text:"row4 col4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="5"}, {role="cell"}]
+++++++++++TextView text:"row4 col5" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-rowindex="5"}, {role="row"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="2"}, {role="cell"}]
+++++++++++TextView text:"row5 col2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="3"}, {role="cell"}]
+++++++++++TextView text:"row5 col3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="4"}, {role="cell"}]
+++++++++++TextView text:"row5 col4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="5"}, {role="cell"}]
+++++++++++TextView text:"row5 col5" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-rowindex="6"}, {role="row"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="2"}, {role="cell"}]
+++++++++++TextView text:"row6 col2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="3"}, {role="cell"}]
+++++++++++TextView text:"row6 col3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="4"}, {role="cell"}]
+++++++++++TextView text:"row6 col4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="5"}, {role="cell"}]
+++++++++++TextView text:"row6 col5" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-col-row-index-undefined-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-col-row-index-undefined-expected-android-assist-data.txt
index 1247fff..e9eb2c60 100644
--- a/content/test/data/accessibility/aria/aria-col-row-index-undefined-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-col-row-index-undefined-expected-android-assist-data.txt
@@ -1,25 +1,25 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++GridView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="table"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="rowgroup"]
-++++++View textSize:16.00 style:0 bundle:[aria-rowindex="-1", display="block", htmlTag="div", role="row"]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="-1", display="inline", htmlTag="span", role="columnheader"]
-++++++++++TextView text:"row1 colheader1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="0", display="inline", htmlTag="span", role="columnheader"]
-++++++++++TextView text:"row1 colheader2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="1", display="inline", htmlTag="span", role="columnheader"]
-++++++++++TextView text:"row1 colheader3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="rowgroup"]
-++++++View textSize:16.00 style:0 bundle:[aria-rowindex="0", display="block", htmlTag="div", role="row"]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="-1", display="inline", htmlTag="span", role="cell"]
-++++++++++TextView text:"row2 col1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="0", display="inline", htmlTag="span", role="cell"]
-++++++++++TextView text:"row2 col2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="1", display="inline", htmlTag="span", role="cell"]
-++++++++++TextView text:"row2 col3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[aria-rowindex="1", display="block", htmlTag="div", role="row"]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="-1", display="inline", htmlTag="span", role="cell"]
-++++++++++TextView text:"row3 col1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="0", display="inline", htmlTag="span", role="cell"]
-++++++++++TextView text:"row3 col2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[aria-colindex="1", display="inline", htmlTag="span", role="cell"]
-++++++++++TextView text:"row3 col3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="table"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="rowgroup"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-rowindex="-1"}, {role="row"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="-1"}, {role="columnheader"}]
+++++++++++TextView text:"row1 colheader1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="0"}, {role="columnheader"}]
+++++++++++TextView text:"row1 colheader2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="1"}, {role="columnheader"}]
+++++++++++TextView text:"row1 colheader3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="rowgroup"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-rowindex="0"}, {role="row"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="-1"}, {role="cell"}]
+++++++++++TextView text:"row2 col1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="0"}, {role="cell"}]
+++++++++++TextView text:"row2 col2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="1"}, {role="cell"}]
+++++++++++TextView text:"row2 col3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-rowindex="1"}, {role="row"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="-1"}, {role="cell"}]
+++++++++++TextView text:"row3 col1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="0"}, {role="cell"}]
+++++++++++TextView text:"row3 col2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-colindex="1"}, {role="cell"}]
+++++++++++TextView text:"row3 col3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-columnheader-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-columnheader-expected-android-assist-data.txt
index 87d87de..ed53be9 100644
--- a/content/test/data/accessibility/aria/aria-columnheader-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-columnheader-expected-android-assist-data.txt
@@ -1,17 +1,17 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++GridView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="grid"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View text:"Browser" textSize:16.00 style:0 bundle:[aria-label="Browser", display="inline", htmlTag="span", role="columnheader"]
-++++++++TextView text:"Browser" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View text:"Rendering Engine" textSize:16.00 style:0 bundle:[aria-label="Rendering Engine", display="inline", htmlTag="span", role="columnheader"]
-++++++++TextView text:"Rendering Engine" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"Chrome" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"Blink" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"Safari" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"WebKit" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="grid"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View text:"Browser" textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-label="Browser"}, {role="columnheader"}]
+++++++++TextView text:"Browser" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View text:"Rendering Engine" textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-label="Rendering Engine"}, {role="columnheader"}]
+++++++++TextView text:"Rendering Engine" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"Chrome" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"Blink" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"Safari" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"WebKit" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-combobox-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-combobox-expected-android-assist-data.txt
index 67033cd7..a96329f6 100644
--- a/content/test/data/accessibility/aria/aria-combobox-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-combobox-expected-android-assist-data.txt
@@ -1,12 +1,12 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="state_label"]
-++++TextView text:"State" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++EditText text:"State" textSize:13.33 style:0 bundle:[aria-activedescendant="state2", aria-autocomplete="list", aria-expanded="true", aria-haspopup="listbox", aria-labelledby="state_label", aria-owns="state_list", aria-readonly="true", autofocus="", display="inline-block", htmlTag="input", role="combobox", type="text"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", id="state_list", onclick="console.log('hi')", role="listbox"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", id="state1", role="option"]
-++++++TextView text:"• " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"Alabama" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", id="state2", role="option"]
-++++++TextView text:"• " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"Alaska" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="state_label"}]
+++++TextView text:"State" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++EditText text:"State" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-activedescendant="state2"}, {aria-autocomplete="list"}, {aria-expanded="true"}, {aria-haspopup="listbox"}, {aria-labelledby="state_label"}, {aria-owns="state_list"}, {aria-readonly="true"}, {autofocus=""}, {role="combobox"}, {type="text"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {id="state_list"}, {onclick="console.log('hi')"}, {role="listbox"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {id="state1"}, {role="option"}]
+++++++TextView text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"Alabama" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {id="state2"}, {role="option"}]
+++++++TextView text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"Alaska" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-combobox-implicit-haspopup-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-combobox-implicit-haspopup-expected-android-assist-data.txt
index f25abc2..34830e45 100644
--- a/content/test/data/accessibility/aria/aria-combobox-implicit-haspopup-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-combobox-implicit-haspopup-expected-android-assist-data.txt
@@ -1,8 +1,8 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View text:"ComboBoxGrouping" textSize:16.00 style:0 bundle:[aria-label="ComboBoxGrouping", display="block", htmlTag="div", role="combobox"]
-++++EditText textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++EditText text:"TextFieldWithComboBox" textSize:13.33 style:0 bundle:[aria-label="TextFieldWithComboBox", display="inline-block", htmlTag="input", role="combobox"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++Spinner text:"Select" textSize:16.00 style:0 bundle:[aria-label="ComboBoxMenuButton"", display="block", htmlTag="div", role="combobox", tabindex="0"]
-++++TextView text:"Select" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View text:"ComboBoxGrouping" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="ComboBoxGrouping"}, {role="combobox"}]
+++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++EditText text:"TextFieldWithComboBox" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-label="TextFieldWithComboBox"}, {role="combobox"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++Spinner text:"Select" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="ComboBoxMenuButton""}, {role="combobox"}, {tabindex="0"}]
+++++TextView text:"Select" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-combobox-uneditable-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-combobox-uneditable-expected-android-assist-data.txt
index 8d6a22d..eeb93c0 100644
--- a/content/test/data/accessibility/aria/aria-combobox-uneditable-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-combobox-uneditable-expected-android-assist-data.txt
@@ -1,12 +1,12 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="combo1-label"]
-++++TextView text:"Choose a fruit, with text content" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++Spinner text:"Apple" textSize:16.00 style:0 bundle:[aria-activedescendant="combo1-0", aria-controls="listbox1", aria-expanded="false", aria-haspopup="listbox", aria-labelledby="combo1-label", display="block", htmlTag="div", role="combobox", tabindex="0"]
-++++TextView text:"Apple" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="listbox1", onclick="console.log('hi')", role="listbox"]
-++++View textSize:16.00 style:0 bundle:[aria-selected="true", display="block", htmlTag="div", id="combo1-0", role="option"]
-++++++TextView text:"Apple" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="combo1-1", role="option"]
-++++++TextView text:"Banana" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="combo1-2", role="option"]
-++++++TextView text:"Cherry" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="combo1-label"}]
+++++TextView text:"Choose a fruit, with text content" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Spinner text:"Apple" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-activedescendant="combo1-0"}, {aria-controls="listbox1"}, {aria-expanded="false"}, {aria-haspopup="listbox"}, {aria-labelledby="combo1-label"}, {role="combobox"}, {tabindex="0"}]
+++++TextView text:"Apple" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="listbox1"}, {onclick="console.log('hi')"}, {role="listbox"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-selected="true"}, {id="combo1-0"}, {role="option"}]
+++++++TextView text:"Apple" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="combo1-1"}, {role="option"}]
+++++++TextView text:"Banana" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="combo1-2"}, {role="option"}]
+++++++TextView text:"Cherry" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-complementary-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-complementary-expected-android-assist-data.txt
index f405b9b..5418b027 100644
--- a/content/test/data/accessibility/aria/aria-complementary-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-complementary-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="complementary"]
-++++TextView text:"This is ARIA role complementary." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="complementary"}]
+++++TextView text:"This is ARIA role complementary." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-contentinfo-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-contentinfo-expected-android-assist-data.txt
index 25a3ff26..51b581e 100644
--- a/content/test/data/accessibility/aria/aria-contentinfo-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-contentinfo-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="contentinfo"]
-++++TextView text:"This is ARIA role contentinfo." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="contentinfo"}]
+++++TextView text:"This is ARIA role contentinfo." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-controls-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-controls-expected-android-assist-data.txt
index 79dea4c..5fc19c5 100644
--- a/content/test/data/accessibility/aria/aria-controls-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-controls-expected-android-assist-data.txt
@@ -1,11 +1,11 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", role="menubar", style="list-style-type: none"]
-++++MenuItem textSize:16.00 style:0 bundle:[aria-controls="filemenu", display="list-item", htmlTag="li", role="menuitem"]
-++++++TextView text:"File" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++MenuItem textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", role="menuitem"]
-++++++TextView text:"Edit" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"File" textSize:16.00 style:0 bundle:[aria-label="File", display="block", htmlTag="ul", id="filemenu", role="menu", style="list-style-type: none"]
-++++MenuItem textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", role="menuitem"]
-++++++TextView text:"New" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++MenuItem textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", role="menuitem"]
-++++++TextView text:"Open" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {role="menubar"}, {style="list-style-type: none"}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-controls="filemenu"}, {role="menuitem"}]
+++++++TextView text:"File" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {role="menuitem"}]
+++++++TextView text:"Edit" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"File" textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {aria-label="File"}, {id="filemenu"}, {role="menu"}, {style="list-style-type: none"}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {role="menuitem"}]
+++++++TextView text:"New" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {role="menuitem"}]
+++++++TextView text:"Open" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-current-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-current-expected-android-assist-data.txt
index 43dd88d..3fb12b9 100644
--- a/content/test/data/accessibility/aria/aria-current-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-current-expected-android-assist-data.txt
@@ -1,40 +1,40 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#section1", htmlTag="a"]
-++++TextView text:"Section one" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#section2", htmlTag="a"]
-++++TextView text:"Section two" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:4 fgColor:-16776978 bundle:[aria-current="location", display="inline", href="#section3", htmlTag="a"]
-++++TextView text:"Section three" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++View text:"\n" textSize:16.00 style:0 bundle:[display="", htmlTag="br"]
-++View textSize:32.00 style:1 bundle:[display="block", htmlTag="h1", id="section1"]
-++++TextView text:"Section one heading" textSize:32.00 style:1 bundle:[display="", htmlTag=""]
-++View textSize:32.00 style:1 bundle:[display="block", htmlTag="h1", id="section2"]
-++++TextView text:"Section two heading" textSize:32.00 style:1 bundle:[display="", htmlTag=""]
-++View textSize:32.00 style:1 bundle:[display="block", htmlTag="h1", id="section3"]
-++++TextView text:"Section three heading" textSize:32.00 style:1 bundle:[display="", htmlTag=""]
-++View text:"\n" textSize:16.00 style:0 bundle:[display="", htmlTag="br"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++TextView text:"Span 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-current="true", display="inline", htmlTag="span"]
-++++++TextView text:"Span 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"Span 3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-current="true", display="block", htmlTag="p"]
-++++TextView text:"aria-current is true" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-current="false", display="block", htmlTag="p"]
-++++TextView text:"aria-current is false" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-current="time", display="block", htmlTag="p"]
-++++TextView text:"aria-current is time" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-current="date", display="block", htmlTag="p"]
-++++TextView text:"aria-current is date" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-current="location", display="block", htmlTag="p"]
-++++TextView text:"aria-current is location" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-current="step", display="block", htmlTag="p"]
-++++TextView text:"aria-current is step" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-current="page", display="block", htmlTag="p"]
-++++TextView text:"aria-current is page" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-current="", display="block", htmlTag="p"]
-++++TextView text:"aria-current is empty string" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#section1"}]
+++++TextView text:"Section one" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#section2"}]
+++++TextView text:"Section two" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {aria-current="location"}, {href="#section3"}]
+++++TextView text:"Section three" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"\n" textSize:16.0 style:0 htmlInfo:[{htmlTag="br"}, {display=""}]
+++View textSize:32.0 style:1 htmlInfo:[{htmlTag="h1"}, {display="block"}, {id="section1"}]
+++++TextView text:"Section one heading" textSize:32.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:32.0 style:1 htmlInfo:[{htmlTag="h1"}, {display="block"}, {id="section2"}]
+++++TextView text:"Section two heading" textSize:32.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:32.0 style:1 htmlInfo:[{htmlTag="h1"}, {display="block"}, {id="section3"}]
+++++TextView text:"Section three heading" textSize:32.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"\n" textSize:16.0 style:0 htmlInfo:[{htmlTag="br"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++TextView text:"Span 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-current="true"}]
+++++++TextView text:"Span 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"Span 3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {aria-current="true"}]
+++++TextView text:"aria-current is true" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {aria-current="false"}]
+++++TextView text:"aria-current is false" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {aria-current="time"}]
+++++TextView text:"aria-current is time" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {aria-current="date"}]
+++++TextView text:"aria-current is date" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {aria-current="location"}]
+++++TextView text:"aria-current is location" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {aria-current="step"}]
+++++TextView text:"aria-current is step" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {aria-current="page"}]
+++++TextView text:"aria-current is page" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {aria-current=""}]
+++++TextView text:"aria-current is empty string" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-definition-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-definition-expected-android-assist-data.txt
index 68dcfb1..541f43d9 100644
--- a/content/test/data/accessibility/aria/aria-definition-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-definition-expected-android-assist-data.txt
@@ -1,2 +1,2 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="definition"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="definition"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-describedby-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-describedby-expected-android-assist-data.txt
index 6b05c92..0179272 100644
--- a/content/test/data/accessibility/aria/aria-describedby-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-describedby-expected-android-assist-data.txt
@@ -1,7 +1,7 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++EditText text:"Your username should be your email id" textSize:13.33 style:0 bundle:[aria-describedby="username-tip", display="inline-block", htmlTag="input", id="username", type="text"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="username-tip", role="tooltip"]
-++++TextView text:"Your username should be your email id" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++EditText text:"mmddyy" textSize:13.33 style:0 bundle:[aria-describedby="date-desc", display="inline-block", htmlTag="input", type="text"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++EditText text:"Your username should be your email id" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-describedby="username-tip"}, {id="username"}, {type="text"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="username-tip"}, {role="tooltip"}]
+++++TextView text:"Your username should be your email id" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++EditText text:"mmddyy" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-describedby="date-desc"}, {type="text"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-description-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-description-expected-android-assist-data.txt
index f542aea..f9eefb4 100644
--- a/content/test/data/accessibility/aria/aria-description-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-description-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View text:"description Text-description" textSize:16.00 style:0 bundle:[aria-description="Text-description", aria-label="description", display="block", htmlTag="div"]
-++View text:"both Description from describedby" textSize:16.00 style:0 bundle:[aria-describedby="desc1", aria-description="describedby overrides description", aria-label="both", display="block", htmlTag="div"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="desc1", role="tooltip"]
-++++TextView text:"Description from describedby" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View text:"description Text-description" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-description="Text-description"}, {aria-label="description"}]
+++View text:"both Description from describedby" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-describedby="desc1"}, {aria-description="describedby overrides description"}, {aria-label="both"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="desc1"}, {role="tooltip"}]
+++++TextView text:"Description from describedby" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-details-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-details-expected-android-assist-data.txt
index e90a239..9e59f76 100644
--- a/content/test/data/accessibility/aria/aria-details-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-details-expected-android-assist-data.txt
@@ -1,14 +1,14 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++EditText textSize:13.33 style:0 bundle:[aria-details="details", display="inline-block", htmlTag="input"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p", id="details"]
-++++TextView text:"Details" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"This " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-details="details2 details3", display="inline", htmlTag="span"]
-++++++TextView text:"text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" has details" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="details2", role="group"]
-++++TextView text:"Text details" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++Image text:"Image details" textSize:16.00 style:0 bundle:[alt="Image details", display="inline", htmlTag="img", id="details3"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-details="details"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {id="details"}]
+++++TextView text:"Details" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"This " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-details="details2 details3"}]
+++++++TextView text:"text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" has details" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="details2"}, {role="group"}]
+++++TextView text:"Text details" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Image text:"Image details" textSize:16.0 style:0 htmlInfo:[{htmlTag="img"}, {display="inline"}, {alt="Image details"}, {id="details3"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-details-multiple-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-details-multiple-expected-android-assist-data.txt
index 0a01dd13..d8f6b12 100644
--- a/content/test/data/accessibility/aria/aria-details-multiple-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-details-multiple-expected-android-assist-data.txt
@@ -1,11 +1,11 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++TextView text:"Some " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-details="comment footnote definition", display="inline", htmlTag="span", id="annotated-text", role="mark"]
-++++TextView text:"highlighted text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++TextView text:" example." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="comment", role="comment"]
-++++TextView text:"Good job!" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="footnote", role="doc-footnote"]
-++++TextView text:"Some footnote." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="definition", role="definition"]
-++++TextView text:"The meaning is." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++TextView text:"Some " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-details="comment footnote definition"}, {id="annotated-text"}, {role="mark"}]
+++++TextView text:"highlighted text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++TextView text:" example." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="comment"}, {role="comment"}]
+++++TextView text:"Good job!" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="footnote"}, {role="doc-footnote"}]
+++++TextView text:"Some footnote." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="definition"}, {role="definition"}]
+++++TextView text:"The meaning is." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-dialog-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-dialog-expected-android-assist-data.txt
index ec5312d..6b3464b 100644
--- a/content/test/data/accessibility/aria/aria-dialog-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-dialog-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++Dialog textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="dialog"]
-++++TextView text:"This is ARIA dialog." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++Dialog textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="dialog"}]
+++++TextView text:"This is ARIA dialog." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-directory-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-directory-expected-android-assist-data.txt
index 8fba61ac..a83c31b 100644
--- a/content/test/data/accessibility/aria/aria-directory-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-directory-expected-android-assist-data.txt
@@ -1,2 +1,2 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="directory"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="directory"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-disabled-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-disabled-expected-android-assist-data.txt
index 74f80dd..45eeeef 100644
--- a/content/test/data/accessibility/aria/aria-disabled-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-disabled-expected-android-assist-data.txt
@@ -1,22 +1,22 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++EditText textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", type="text"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++EditText textSize:13.33 style:0 bundle:[aria-disabled="true", display="inline-block", htmlTag="input", type="text"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++EditText textSize:13.33 style:0 bundle:[aria-disabled="false", display="inline-block", htmlTag="input", type="text"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++View textSize:16.00 style:0 bundle:[aria-disabled="true", display="block", htmlTag="div"]
-++++EditText textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", type="text"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++EditText textSize:13.33 style:0 bundle:[aria-disabled="true", display="inline-block", htmlTag="input", type="text"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++EditText textSize:13.33 style:0 bundle:[aria-disabled="false", display="inline-block", htmlTag="input", type="text"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++View textSize:16.00 style:0 bundle:[aria-disabled="false", display="block", htmlTag="div"]
-++++EditText textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", type="text"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++EditText textSize:13.33 style:0 bundle:[aria-disabled="true", display="inline-block", htmlTag="input", type="text"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++EditText textSize:13.33 style:0 bundle:[aria-disabled="false", display="inline-block", htmlTag="input", type="text"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="text"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-disabled="true"}, {type="text"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-disabled="false"}, {type="text"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-disabled="true"}]
+++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="text"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-disabled="true"}, {type="text"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-disabled="false"}, {type="text"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-disabled="false"}]
+++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="text"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-disabled="true"}, {type="text"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-disabled="false"}, {type="text"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-document-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-document-expected-android-assist-data.txt
index 1a636f2..8ef5817b 100644
--- a/content/test/data/accessibility/aria/aria-document-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-document-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="document"]
-++++TextView text:"aria role document" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="document"}]
+++++TextView text:"aria role document" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-emphasis-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-emphasis-expected-android-assist-data.txt
index 7fb9e24..c815501 100644
--- a/content/test/data/accessibility/aria/aria-emphasis-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-emphasis-expected-android-assist-data.txt
@@ -1,7 +1,7 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="emphasis"]
-++++TextView text:"role" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++TextView text:"element (no name)" textSize:16.00 style:2 bundle:[display="", htmlTag=""]
-++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"include me" textSize:16.00 style:2 bundle:[aria-label="include me", display="inline", htmlTag="em"]
-++++TextView text:"element (with name)" textSize:16.00 style:2 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="emphasis"}]
+++++TextView text:"role" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++TextView text:"element (no name)" textSize:16.0 style:2 htmlInfo:[{htmlTag=""}, {display=""}]
+++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"include me" textSize:16.0 style:2 htmlInfo:[{htmlTag="em"}, {display="inline"}, {aria-label="include me"}]
+++++TextView text:"element (with name)" textSize:16.0 style:2 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-errormessage-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-errormessage-expected-android-assist-data.txt
index 7a5d645..a4c2f38 100644
--- a/content/test/data/accessibility/aria/aria-errormessage-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-errormessage-expected-android-assist-data.txt
@@ -1,18 +1,18 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++EditText text:"Invalid is true" textSize:13.33 style:0 bundle:[aria-errormessage="error1", aria-invalid="true", aria-label="Invalid is true", display="inline-block", htmlTag="input"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++EditText text:"Invalid is true with multiple errors" textSize:13.33 style:0 bundle:[aria-errormessage="error1 error2", aria-invalid="true", aria-label="Invalid is true with multiple errors", display="inline-block", htmlTag="input"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++EditText text:"Invalid is false" textSize:13.33 style:0 bundle:[aria-errormessage="error3", aria-invalid="false", aria-label="Invalid is false", display="inline-block", htmlTag="input"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++EditText text:"Invalid is not set" textSize:13.33 style:0 bundle:[aria-errormessage="error4", aria-label="Invalid is not set", display="inline-block", htmlTag="input"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p", id="error1"]
-++++TextView text:"Error for invalid input" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p", id="error2"]
-++++TextView text:"Another error for invalid input" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p", id="error3"]
-++++TextView text:"Error for input which is not invalid" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p", id="error4"]
-++++TextView text:"Error for input with invalid not set" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++EditText text:"Invalid is true" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-errormessage="error1"}, {aria-invalid="true"}, {aria-label="Invalid is true"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++EditText text:"Invalid is true with multiple errors" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-errormessage="error1 error2"}, {aria-invalid="true"}, {aria-label="Invalid is true with multiple errors"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++EditText text:"Invalid is false" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-errormessage="error3"}, {aria-invalid="false"}, {aria-label="Invalid is false"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++EditText text:"Invalid is not set" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-errormessage="error4"}, {aria-label="Invalid is not set"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {id="error1"}]
+++++TextView text:"Error for invalid input" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {id="error2"}]
+++++TextView text:"Another error for invalid input" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {id="error3"}]
+++++TextView text:"Error for input which is not invalid" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {id="error4"}]
+++++TextView text:"Error for input with invalid not set" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-expanded-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-expanded-expected-android-assist-data.txt
index abaa9ca7..1d015c77 100644
--- a/content/test/data/accessibility/aria/aria-expanded-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-expanded-expected-android-assist-data.txt
@@ -1,15 +1,15 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", role="menu", style="list-style-type: none"]
-++++MenuItem textSize:16.00 style:0 bundle:[aria-expanded="false", aria-haspopup="true", display="list-item", htmlTag="li", role="menuitem"]
-++++++TextView text:"New" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++MenuItem textSize:16.00 style:0 bundle:[aria-expanded="true", aria-haspopup="true", display="list-item", htmlTag="li", role="menuitem"]
-++++++TextView text:"Open" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++MenuItem textSize:16.00 style:0 bundle:[aria-expanded="false", display="list-item", htmlTag="li", role="menuitem"]
-++++++TextView text:"Save" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++MenuItem textSize:16.00 style:0 bundle:[aria-expanded="true", display="list-item", htmlTag="li", role="menuitem"]
-++++++TextView text:"Quit" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"ARIA separator. aria-expanded value set to false." textSize:16.00 style:0 bundle:[aria-expanded="false", display="block", htmlTag="div", role="separator"]
-++++TextView text:"ARIA separator. aria-expanded value set to false." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"ARIA separator. aria-expanded value set to true." textSize:16.00 style:0 bundle:[aria-expanded="true", display="block", htmlTag="div", role="separator"]
-++++TextView text:"ARIA separator. aria-expanded value set to true." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-expanded="true", display="block", htmlTag="hr", role="separator"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {role="menu"}, {style="list-style-type: none"}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-expanded="false"}, {aria-haspopup="true"}, {role="menuitem"}]
+++++++TextView text:"New" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-expanded="true"}, {aria-haspopup="true"}, {role="menuitem"}]
+++++++TextView text:"Open" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-expanded="false"}, {role="menuitem"}]
+++++++TextView text:"Save" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-expanded="true"}, {role="menuitem"}]
+++++++TextView text:"Quit" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"ARIA separator. aria-expanded value set to false." textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-expanded="false"}, {role="separator"}]
+++++TextView text:"ARIA separator. aria-expanded value set to false." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"ARIA separator. aria-expanded value set to true." textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-expanded="true"}, {role="separator"}]
+++++TextView text:"ARIA separator. aria-expanded value set to true." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="hr"}, {display="block"}, {aria-expanded="true"}, {role="separator"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-figure-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-figure-expected-android-assist-data.txt
index b5537a5..e004eca 100644
--- a/content/test/data/accessibility/aria/aria-figure-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-figure-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="figure"]
-++++TextView text:"Figure" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="figure"}]
+++++TextView text:"Figure" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-flowto-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-flowto-expected-android-assist-data.txt
index 99fa582..f7f57d2 100644
--- a/content/test/data/accessibility/aria/aria-flowto-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-flowto-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View text:"current" textSize:16.00 style:0 bundle:[aria-flowto="next", aria-label="current", display="block", htmlTag="section"]
-++++TextView text:"Lorem ipsum" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"next" textSize:16.00 style:0 bundle:[aria-label="next", display="block", htmlTag="footer", id="next"]
-++++TextView text:"dolor sit amet" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View text:"current" textSize:16.0 style:0 htmlInfo:[{htmlTag="section"}, {display="block"}, {aria-flowto="next"}, {aria-label="current"}]
+++++TextView text:"Lorem ipsum" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"next" textSize:16.0 style:0 htmlInfo:[{htmlTag="footer"}, {display="block"}, {aria-label="next"}, {id="next"}]
+++++TextView text:"dolor sit amet" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-form-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-form-expected-android-assist-data.txt
index 8260037..46001d69 100644
--- a/content/test/data/accessibility/aria/aria-form-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-form-expected-android-assist-data.txt
@@ -1,14 +1,14 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="fieldset", role="form"]
-++++TextView text:"Unnamed ARIA form: must fall back to the native role." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="form"]
-++++TextView text:"Unnamed ARIA form on plain div uses generic container role." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"Named form" textSize:16.00 style:0 bundle:[aria-label="Named form", display="block", htmlTag="div", role="form"]
-++++TextView text:"Named ARIA form#1 gets the form role." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"Named ARIA form#2 gets the form role." textSize:16.00 style:0 bundle:[aria-labelledby="form-name", display="block", htmlTag="div", role="form"]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="form-name"]
-++++++TextView text:"Named ARIA form#2 gets the form role." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"Named form" textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="form", title="Named form"]
-++++TextView text:"Named ARIA form#3 gets the form role." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-roledescription="form", display="block", htmlTag="div", role="form"]
-++++TextView text:"An aria-rolescription works on a nameless role=form." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="fieldset"}, {display="block"}, {role="form"}]
+++++TextView text:"Unnamed ARIA form: must fall back to the native role." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="form"}]
+++++TextView text:"Unnamed ARIA form on plain div uses generic container role." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"Named form" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Named form"}, {role="form"}]
+++++TextView text:"Named ARIA form#1 gets the form role." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"Named ARIA form#2 gets the form role." textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-labelledby="form-name"}, {role="form"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="form-name"}]
+++++++TextView text:"Named ARIA form#2 gets the form role." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"Named form" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="form"}, {title="Named form"}]
+++++TextView text:"Named ARIA form#3 gets the form role." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-roledescription="form"}, {role="form"}]
+++++TextView text:"An aria-rolescription works on a nameless role=form." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-generic-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-generic-expected-android-assist-data.txt
index 02420d1..b5eea9f1 100644
--- a/content/test/data/accessibility/aria/aria-generic-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-generic-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="fieldset", role="generic"]
-++++TextView text:"content" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="fieldset"}, {display="block"}, {role="generic"}]
+++++TextView text:"content" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-grid-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-grid-expected-android-assist-data.txt
index 93bf8be..89d7418 100644
--- a/content/test/data/accessibility/aria/aria-grid-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-grid-expected-android-assist-data.txt
@@ -1,12 +1,12 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++GridView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="grid"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="columnheader"]
-++++++++TextView text:"Browser" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="columnheader"]
-++++++++TextView text:"Rendering Engine" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"Chrome" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"Blink" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="grid"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="columnheader"}]
+++++++++TextView text:"Browser" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="columnheader"}]
+++++++++TextView text:"Rendering Engine" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"Chrome" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"Blink" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-gridcell-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-gridcell-expected-android-assist-data.txt
index 6acf9c7..c6886eb 100644
--- a/content/test/data/accessibility/aria/aria-gridcell-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-gridcell-expected-android-assist-data.txt
@@ -1,12 +1,12 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++GridView textSize:16.00 style:0 bundle:[aria-multiselectable="true", display="block", htmlTag="div", role="grid"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="columnheader"]
-++++++++TextView text:"Browser" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="columnheader"]
-++++++++TextView text:"Rendering Engine" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"Chrome" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"Blink" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-multiselectable="true"}, {role="grid"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="columnheader"}]
+++++++++TextView text:"Browser" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="columnheader"}]
+++++++++TextView text:"Rendering Engine" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"Chrome" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"Blink" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-group-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-group-expected-android-assist-data.txt
index c4c9a9f..89805e9 100644
--- a/content/test/data/accessibility/aria/aria-group-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-group-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="group"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="link"]
-++++++TextView text:"Group Link1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="link"]
-++++++TextView text:"Group Link2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="group"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="link"}]
+++++++TextView text:"Group Link1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="link"}]
+++++++TextView text:"Group Link2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-haspopup-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-haspopup-expected-android-assist-data.txt
index b92c391..f7d5952 100644
--- a/content/test/data/accessibility/aria/aria-haspopup-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-haspopup-expected-android-assist-data.txt
@@ -1,10 +1,10 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++Spinner textSize:16.00 style:0 bundle:[aria-haspopup="true", display="block", htmlTag="div", role="combobox", tabindex="0"]
-++Spinner textSize:16.00 style:0 bundle:[aria-haspopup="false", display="block", htmlTag="div", role="combobox", tabindex="1"]
-++Spinner textSize:16.00 style:0 bundle:[aria-haspopup="menu", display="block", htmlTag="div", role="combobox", tabindex="2"]
-++Spinner textSize:16.00 style:0 bundle:[aria-haspopup="listbox", display="block", htmlTag="div", role="combobox", tabindex="3"]
-++Spinner textSize:16.00 style:0 bundle:[aria-haspopup="grid", display="block", htmlTag="div", role="combobox", tabindex="4"]
-++Spinner textSize:16.00 style:0 bundle:[aria-haspopup="dialog", display="block", htmlTag="div", role="combobox", tabindex="5"]
-++Spinner textSize:16.00 style:0 bundle:[aria-haspopup="invalid", display="block", htmlTag="div", role="combobox", tabindex="6"]
-++Spinner textSize:16.00 style:0 bundle:[aria-haspopup="", display="block", htmlTag="div", role="combobox", tabindex="7"]
-++Spinner textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="combobox", tabindex="8"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++Spinner textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-haspopup="true"}, {role="combobox"}, {tabindex="0"}]
+++Spinner textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-haspopup="false"}, {role="combobox"}, {tabindex="1"}]
+++Spinner textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-haspopup="menu"}, {role="combobox"}, {tabindex="2"}]
+++Spinner textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-haspopup="listbox"}, {role="combobox"}, {tabindex="3"}]
+++Spinner textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-haspopup="grid"}, {role="combobox"}, {tabindex="4"}]
+++Spinner textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-haspopup="dialog"}, {role="combobox"}, {tabindex="5"}]
+++Spinner textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-haspopup="invalid"}, {role="combobox"}, {tabindex="6"}]
+++Spinner textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-haspopup=""}, {role="combobox"}, {tabindex="7"}]
+++Spinner textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="combobox"}, {tabindex="8"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-heading-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-heading-expected-android-assist-data.txt
index 11befb4..871278a 100644
--- a/content/test/data/accessibility/aria/aria-heading-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-heading-expected-android-assist-data.txt
@@ -1,16 +1,16 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[aria-level="1", display="block", htmlTag="div", role="heading"]
-++++TextView text:"ARIA Heading 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-level="2", display="block", htmlTag="div", role="heading"]
-++++TextView text:"ARIA Heading 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-level="3", display="block", htmlTag="div", role="heading"]
-++++TextView text:"ARIA Heading 3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-level="4", display="block", htmlTag="div", role="heading"]
-++++TextView text:"ARIA Heading 4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-level="5", display="block", htmlTag="div", role="heading"]
-++++TextView text:"ARIA Heading 5" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-level="6", display="block", htmlTag="div", role="heading"]
-++++TextView text:"ARIA Heading 6" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="heading"]
-++++++TextView text:"Heading" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-level="1"}, {role="heading"}]
+++++TextView text:"ARIA Heading 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-level="2"}, {role="heading"}]
+++++TextView text:"ARIA Heading 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-level="3"}, {role="heading"}]
+++++TextView text:"ARIA Heading 3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-level="4"}, {role="heading"}]
+++++TextView text:"ARIA Heading 4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-level="5"}, {role="heading"}]
+++++TextView text:"ARIA Heading 5" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-level="6"}, {role="heading"}]
+++++TextView text:"ARIA Heading 6" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="heading"}]
+++++++TextView text:"Heading" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-hidden-described-by-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-hidden-described-by-expected-android-assist-data.txt
index a680497a..3b9232a 100644
--- a/content/test/data/accessibility/aria/aria-hidden-described-by-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-hidden-described-by-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++View text:"span-A span-1" textSize:16.00 style:0 bundle:[aria-describedby="s1", aria-label="span-A", display="inline", htmlTag="span"]
-++++View text:"span-B span-2" textSize:16.00 style:0 bundle:[aria-describedby="s2", aria-label="span-B", display="inline", htmlTag="span"]
-++++View text:"span-C span-3" textSize:16.00 style:0 bundle:[aria-describedby="s3", aria-label="span-C", display="inline", htmlTag="span"]
-++++View text:"span-D span-4" textSize:16.00 style:0 bundle:[aria-describedby="s4", aria-label="span-D", display="inline", htmlTag="span"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++View text:"span-A span-1" textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-describedby="s1"}, {aria-label="span-A"}]
+++++View text:"span-B span-2" textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-describedby="s2"}, {aria-label="span-B"}]
+++++View text:"span-C span-3" textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-describedby="s3"}, {aria-label="span-C"}]
+++++View text:"span-D span-4" textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-describedby="s4"}, {aria-label="span-D"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-hidden-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-hidden-expected-android-assist-data.txt
index 5698a0a0..b7e0572 100644
--- a/content/test/data/accessibility/aria/aria-hidden-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-hidden-expected-android-assist-data.txt
@@ -1,8 +1,8 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="blockDisplay"]
-++++TextView text:"blockDisplay" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-hidden="false", display="block", htmlTag="div", id="blockDisplayAriaHiddenFalse"]
-++++TextView text:"blockDisplay Hiddenfalse" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:0.00 style:0 fgColor:0 bundle:[aria-hidden="false", display="", htmlTag="div", id="noneDisplayAriaHiddenFalse"]
-++View textSize:16.00 style:0 bundle:[aria-hidden="true", display="block", htmlTag="div", id="blockDisplayAriaHiddenTrueFocusable", tabindex="0"]
-++View textSize:0.00 style:0 fgColor:0 bundle:[aria-hidden="false", display="", htmlTag="h1"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="blockDisplay"}]
+++++TextView text:"blockDisplay" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-hidden="false"}, {id="blockDisplayAriaHiddenFalse"}]
+++++TextView text:"blockDisplay Hiddenfalse" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="div"}, {display=""}, {aria-hidden="false"}, {id="noneDisplayAriaHiddenFalse"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-hidden="true"}, {id="blockDisplayAriaHiddenTrueFocusable"}, {tabindex="0"}]
+++View textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="h1"}, {display=""}, {aria-hidden="false"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-hidden-labelled-by-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-hidden-labelled-by-expected-android-assist-data.txt
index e7a4aff..f2f8ef3 100644
--- a/content/test/data/accessibility/aria/aria-hidden-labelled-by-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-hidden-labelled-by-expected-android-assist-data.txt
@@ -1,8 +1,8 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++View text:"span-2" textSize:16.00 style:0 bundle:[aria-label="span-2", display="inline", htmlTag="span", id="s2"]
-++++View text:"span-4" textSize:16.00 style:0 bundle:[aria-hidden="false", aria-label="span-3", aria-labelledby="s4", display="inline", htmlTag="span", id="s3"]
-++++View text:"span-1" textSize:16.00 style:0 bundle:[aria-label="span-A", aria-labelledby="s1", display="inline", htmlTag="span", role="group"]
-++++View text:"span-2" textSize:16.00 style:0 bundle:[aria-label="span-B", aria-labelledby="s2", display="inline", htmlTag="span", role="group"]
-++++View text:"span-3" textSize:16.00 style:0 bundle:[aria-label="span-C", aria-labelledby="s3", display="inline", htmlTag="span", role="group"]
-++++View text:"span-4" textSize:16.00 style:0 bundle:[aria-label="span-D", aria-labelledby="s4", display="inline", htmlTag="span", role="group"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++View text:"span-2" textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-label="span-2"}, {id="s2"}]
+++++View text:"span-4" textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-hidden="false"}, {aria-label="span-3"}, {aria-labelledby="s4"}, {id="s3"}]
+++++View text:"span-1" textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-label="span-A"}, {aria-labelledby="s1"}, {role="group"}]
+++++View text:"span-2" textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-label="span-B"}, {aria-labelledby="s2"}, {role="group"}]
+++++View text:"span-3" textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-label="span-C"}, {aria-labelledby="s3"}, {role="group"}]
+++++View text:"span-4" textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-label="span-D"}, {aria-labelledby="s4"}, {role="group"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-illegal-val-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-illegal-val-expected-android-assist-data.txt
index be71f0a0..6f3da6c 100644
--- a/content/test/data/accessibility/aria/aria-illegal-val-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-illegal-val-expected-android-assist-data.txt
@@ -1,24 +1,24 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View text:"Atomic illegal" textSize:16.00 style:0 bundle:[aria-atomic="X-ILLEGAL", aria-label="Atomic illegal", display="block", htmlTag="div", role="log"]
-++EditText text:"Autocomplete illegal" textSize:16.00 style:0 bundle:[aria-autocomplete="X-ILLEGAL", aria-label="Autocomplete illegal", display="block", htmlTag="div", role="textbox"]
-++View text:"Busy illegal" textSize:16.00 style:0 bundle:[aria-busy="X-ILLEGAL", aria-label="Busy illegal", display="block", htmlTag="div", role="log"]
-++View text:"Checked illegal" textSize:16.00 style:0 bundle:[aria-checked="X-ILLEGAL", aria-label="Checked illegal", display="block", htmlTag="div", role="treeitem"]
-++View text:"Current illegal" textSize:16.00 style:0 bundle:[aria-current="X-ILLEGAL", aria-label="Current illegal", display="block", htmlTag="div", role="group"]
-++View text:"Disabled illegal" textSize:16.00 style:0 bundle:[aria-disabled="X-ILLEGAL", aria-label="Disabled illegal", display="block", htmlTag="div", role="group"]
-++View text:"Expanded illegal" textSize:16.00 style:0 bundle:[aria-expanded="X-ILLEGAL", aria-label="Expanded illegal", display="block", htmlTag="div", role="treeitem"]
-++View text:"Grabbed illegal" textSize:16.00 style:0 bundle:[aria-grabbed="X-ILLEGAL", aria-label="Grabbed illegal", display="block", htmlTag="div", role="group"]
-++Button text:"Haspopup illegal" textSize:16.00 style:0 bundle:[aria-haspopup="X-ILLEGAL", aria-label="Haspopup illegal", display="block", htmlTag="div", role="button"]
-++View text:"Invalid illegal" textSize:16.00 style:0 bundle:[aria-invalid="X-ILLEGAL", aria-label="Invalid illegal", display="block", htmlTag="div", role="group"]
-++View text:"Live illegal" textSize:16.00 style:0 bundle:[aria-label="Live illegal", aria-live="X-ILLEGAL", display="block", htmlTag="div", role="log"]
-++Dialog text:"Modal illegal" textSize:16.00 style:0 bundle:[aria-label="Modal illegal", aria-modal="X-ILLEGAL", display="block", htmlTag="div", role="dialog"]
-++EditText text:"Multiline illegal" textSize:16.00 style:0 bundle:[aria-label="Multiline illegal", aria-multiline="X-ILLEGAL", display="block", htmlTag="div", role="textbox"]
-++GridView text:"Multiselectable illegal" textSize:16.00 style:0 bundle:[aria-label="Multiselectable illegal", aria-multiselectable="X-ILLEGAL", display="block", htmlTag="div", role="grid"]
-++SeekBar text:"Orientation illegal" textSize:16.00 style:0 bundle:[aria-label="Orientation illegal", aria-orientation="X-ILLEGAL", display="block", htmlTag="div", role="slider"]
-++ToggleButton text:"Pressed illegal" textSize:16.00 style:0 bundle:[aria-label="Pressed illegal", aria-pressed="X-ILLEGAL", display="block", htmlTag="div", role="button"]
-++EditText text:"Readonly illegal" textSize:16.00 style:0 bundle:[aria-label="Readonly illegal", aria-readonly="X-ILLEGAL", display="block", htmlTag="div", role="textbox"]
-++View text:"Relevant illegal" textSize:16.00 style:0 bundle:[aria-label="Relevant illegal", aria-relevant="X-ILLEGAL", display="block", htmlTag="div", role="log"]
-++EditText text:"Required illegal" textSize:16.00 style:0 bundle:[aria-label="Required illegal", aria-required="X-ILLEGAL", display="block", htmlTag="div", role="textbox"]
-++View textSize:16.00 style:0 bundle:[aria-multiselectable="true", display="block", htmlTag="div", role="tree"]
-++++View text:"Selected illegal" textSize:16.00 style:0 bundle:[aria-label="Selected illegal", aria-selected="X-ILLEGAL", display="block", htmlTag="div", role="treeitem"]
-++GridView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="grid"]
-++++View text:"Sort illegal" textSize:16.00 style:0 bundle:[aria-label="Sort illegal", aria-sort="X-ILLEGAL", display="block", htmlTag="div", role="columnheader"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View text:"Atomic illegal" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-atomic="X-ILLEGAL"}, {aria-label="Atomic illegal"}, {role="log"}]
+++EditText text:"Autocomplete illegal" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-autocomplete="X-ILLEGAL"}, {aria-label="Autocomplete illegal"}, {role="textbox"}]
+++View text:"Busy illegal" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-busy="X-ILLEGAL"}, {aria-label="Busy illegal"}, {role="log"}]
+++View text:"Checked illegal" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-checked="X-ILLEGAL"}, {aria-label="Checked illegal"}, {role="treeitem"}]
+++View text:"Current illegal" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-current="X-ILLEGAL"}, {aria-label="Current illegal"}, {role="group"}]
+++View text:"Disabled illegal" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-disabled="X-ILLEGAL"}, {aria-label="Disabled illegal"}, {role="group"}]
+++View text:"Expanded illegal" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-expanded="X-ILLEGAL"}, {aria-label="Expanded illegal"}, {role="treeitem"}]
+++View text:"Grabbed illegal" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-grabbed="X-ILLEGAL"}, {aria-label="Grabbed illegal"}, {role="group"}]
+++Button text:"Haspopup illegal" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-haspopup="X-ILLEGAL"}, {aria-label="Haspopup illegal"}, {role="button"}]
+++View text:"Invalid illegal" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-invalid="X-ILLEGAL"}, {aria-label="Invalid illegal"}, {role="group"}]
+++View text:"Live illegal" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Live illegal"}, {aria-live="X-ILLEGAL"}, {role="log"}]
+++Dialog text:"Modal illegal" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Modal illegal"}, {aria-modal="X-ILLEGAL"}, {role="dialog"}]
+++EditText text:"Multiline illegal" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Multiline illegal"}, {aria-multiline="X-ILLEGAL"}, {role="textbox"}]
+++GridView text:"Multiselectable illegal" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Multiselectable illegal"}, {aria-multiselectable="X-ILLEGAL"}, {role="grid"}]
+++SeekBar text:"Orientation illegal" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Orientation illegal"}, {aria-orientation="X-ILLEGAL"}, {role="slider"}]
+++ToggleButton text:"Pressed illegal" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Pressed illegal"}, {aria-pressed="X-ILLEGAL"}, {role="button"}]
+++EditText text:"Readonly illegal" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Readonly illegal"}, {aria-readonly="X-ILLEGAL"}, {role="textbox"}]
+++View text:"Relevant illegal" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Relevant illegal"}, {aria-relevant="X-ILLEGAL"}, {role="log"}]
+++EditText text:"Required illegal" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Required illegal"}, {aria-required="X-ILLEGAL"}, {role="textbox"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-multiselectable="true"}, {role="tree"}]
+++++View text:"Selected illegal" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Selected illegal"}, {aria-selected="X-ILLEGAL"}, {role="treeitem"}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="grid"}]
+++++View text:"Sort illegal" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Sort illegal"}, {aria-sort="X-ILLEGAL"}, {role="columnheader"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-img-child-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-img-child-expected-android-assist-data.txt
index 727c14e..cd59f5b 100644
--- a/content/test/data/accessibility/aria/aria-img-child-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-img-child-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++Image text:"Img.jpg" textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="img"]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="span-in-img"]
-++++++TextView text:"Img.jpg" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++Image text:"Img.jpg" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="img"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="span-in-img"}]
+++++++TextView text:"Img.jpg" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-img-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-img-expected-android-assist-data.txt
index 03fc043..b17e142 100644
--- a/content/test/data/accessibility/aria/aria-img-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-img-expected-android-assist-data.txt
@@ -1,7 +1,7 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++Image textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="img"]
-++++Image text:"composite-part-1" textSize:16.00 style:0 bundle:[display="inline", htmlTag="img", src="composite-part-1.jpg"]
-++++Image text:"composite-part-2" textSize:16.00 style:0 bundle:[display="inline", htmlTag="img", src="composite-part-2.jpg"]
-++Image textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="image"]
-++++Image text:"composite-part-1" textSize:16.00 style:0 bundle:[display="inline", htmlTag="img", src="composite-part-1.jpg"]
-++++Image text:"composite-part-2" textSize:16.00 style:0 bundle:[display="inline", htmlTag="img", src="composite-part-2.jpg"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="img"}]
+++++Image text:"composite-part-1" textSize:16.0 style:0 htmlInfo:[{htmlTag="img"}, {display="inline"}, {src="composite-part-1.jpg"}]
+++++Image text:"composite-part-2" textSize:16.0 style:0 htmlInfo:[{htmlTag="img"}, {display="inline"}, {src="composite-part-2.jpg"}]
+++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="image"}]
+++++Image text:"composite-part-1" textSize:16.0 style:0 htmlInfo:[{htmlTag="img"}, {display="inline"}, {src="composite-part-1.jpg"}]
+++++Image text:"composite-part-2" textSize:16.0 style:0 htmlInfo:[{htmlTag="img"}, {display="inline"}, {src="composite-part-2.jpg"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-insertion-deletion-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-insertion-deletion-expected-android-assist-data.txt
index 7a497324..64c1f6a7 100644
--- a/content/test/data/accessibility/aria/aria-insertion-deletion-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-insertion-deletion-expected-android-assist-data.txt
@@ -1,9 +1,9 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:8.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"My favorite browser is " textSize:8.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:8.00 style:0 bundle:[display="inline", htmlTag="span", role="deletion"]
-++++++TextView text:"ABC" textSize:8.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:8.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:8.00 style:0 bundle:[display="inline", htmlTag="span", role="insertion"]
-++++++TextView text:"Chrome" textSize:8.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"!" textSize:8.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:8.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"My favorite browser is " textSize:8.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:8.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="deletion"}]
+++++++TextView text:"ABC" textSize:8.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:8.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:8.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="insertion"}]
+++++++TextView text:"Chrome" textSize:8.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"!" textSize:8.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-keyshortcuts-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-keyshortcuts-expected-android-assist-data.txt
index 94ec603..3b7152b 100644
--- a/content/test/data/accessibility/aria/aria-keyshortcuts-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-keyshortcuts-expected-android-assist-data.txt
@@ -1,8 +1,8 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-keyshortcuts="Ctrl+X", display="inline-block", htmlTag="button"]
-++++++TextView text:"Cut" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-keyshortcuts="Ctrl+C", display="inline-block", htmlTag="button"]
-++++++TextView text:"Copy" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-keyshortcuts="Ctrl+V", display="inline-block", htmlTag="button"]
-++++++TextView text:"Paste" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}, {aria-keyshortcuts="Ctrl+X"}]
+++++++TextView text:"Cut" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}, {aria-keyshortcuts="Ctrl+C"}]
+++++++TextView text:"Copy" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}, {aria-keyshortcuts="Ctrl+V"}]
+++++++TextView text:"Paste" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-label-augment-inner-text-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-label-augment-inner-text-expected-android-assist-data.txt
index 7a3f7e3..ea0d3d6c 100644
--- a/content/test/data/accessibility/aria/aria-label-augment-inner-text-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-label-augment-inner-text-expected-android-assist-data.txt
@@ -1,11 +1,11 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#", htmlTag="a"]
-++++++TextView text:"Link" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View text:"AriaLabel" textSize:16.00 style:4 fgColor:-16776978 bundle:[aria-label="AriaLabel", display="inline", href="#", htmlTag="a"]
-++++++TextView text:"Link" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="button"]
-++++++TextView text:"Button" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++++Button text:"AriaLabel" textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-label="AriaLabel", display="inline-block", htmlTag="button"]
-++++++TextView text:"Button" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#"}]
+++++++TextView text:"Link" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View text:"AriaLabel" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {aria-label="AriaLabel"}, {href="#"}]
+++++++TextView text:"Link" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}]
+++++++TextView text:"Button" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Button text:"AriaLabel" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}, {aria-label="AriaLabel"}]
+++++++TextView text:"Button" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-label-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-label-expected-android-assist-data.txt
index 5ef4963..a8d6aff4 100644
--- a/content/test/data/accessibility/aria/aria-label-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-label-expected-android-assist-data.txt
@@ -1,2 +1,2 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++CheckBox text:"aria label" textSize:16.00 style:0 bundle:[aria-label="aria label", display="block", htmlTag="div", role="checkbox"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++CheckBox text:"aria label" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="aria label"}, {role="checkbox"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-labelledby-heading-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-labelledby-heading-expected-android-assist-data.txt
index 3361eda..f4221e68 100644
--- a/content/test/data/accessibility/aria/aria-labelledby-heading-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-labelledby-heading-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++EditText text:"h2" textSize:13.33 style:0 bundle:[aria-labelledby="h2", display="inline-block", htmlTag="input"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++View textSize:24.00 style:1 bundle:[display="block", htmlTag="h2", id="h2"]
-++++TextView text:"h2" textSize:24.00 style:1 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++EditText text:"h2" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-labelledby="h2"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++View textSize:24.0 style:1 htmlInfo:[{htmlTag="h2"}, {display="block"}, {id="h2"}]
+++++TextView text:"h2" textSize:24.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-list-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-list-expected-android-assist-data.txt
index 0cbeeffe..1100512 100644
--- a/content/test/data/accessibility/aria/aria-list-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-list-expected-android-assist-data.txt
@@ -1,8 +1,8 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="list"]
-++++View text:"1" textSize:16.00 style:0 bundle:[aria-label="1", display="block", htmlTag="div", role="listitem"]
-++++++TextView text:"Item 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View text:"2" textSize:16.00 style:0 bundle:[aria-label="2", display="block", htmlTag="div", role="listitem"]
-++++++TextView text:"Item 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View text:"3" textSize:16.00 style:0 bundle:[aria-label="3", display="block", htmlTag="div", role="listitem"]
-++++++TextView text:"Item 3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="list"}]
+++++View text:"1" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="1"}, {role="listitem"}]
+++++++TextView text:"Item 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View text:"2" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="2"}, {role="listitem"}]
+++++++TextView text:"Item 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View text:"3" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="3"}, {role="listitem"}]
+++++++TextView text:"Item 3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-listbox-aria-selected-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-listbox-aria-selected-expected-android-assist-data.txt
index 4f12694cd..eae12bd 100644
--- a/content/test/data/accessibility/aria/aria-listbox-aria-selected-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-listbox-aria-selected-expected-android-assist-data.txt
@@ -1,12 +1,12 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ListView textSize:16.00 style:0 bundle:[aria-activedescendant="it1", aria-multiselectable="true", display="block", htmlTag="div", role="listbox"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="it1", role="option"]
-++++++TextView text:"Item 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="it2", role="option"]
-++++++TextView text:"Item 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-selected="false", display="block", htmlTag="div", id="it3", role="option"]
-++++++TextView text:"Item 3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-selected="true", display="block", htmlTag="div", id="it4", role="option"]
-++++++TextView text:"Item 4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-selected="true", display="block", htmlTag="div", id="it5", role="option"]
-++++++TextView text:"Item 5" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-activedescendant="it1"}, {aria-multiselectable="true"}, {role="listbox"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="it1"}, {role="option"}]
+++++++TextView text:"Item 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="it2"}, {role="option"}]
+++++++TextView text:"Item 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-selected="false"}, {id="it3"}, {role="option"}]
+++++++TextView text:"Item 3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-selected="true"}, {id="it4"}, {role="option"}]
+++++++TextView text:"Item 4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-selected="true"}, {id="it5"}, {role="option"}]
+++++++TextView text:"Item 5" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-listbox-disabled-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-listbox-disabled-expected-android-assist-data.txt
index cd71ae1..dedfa63 100644
--- a/content/test/data/accessibility/aria/aria-listbox-disabled-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-listbox-disabled-expected-android-assist-data.txt
@@ -1,14 +1,14 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:32.00 style:1 bundle:[display="block", htmlTag="h1"]
-++++TextView text:"Start of test: striped should have selected state" textSize:32.00 style:1 bundle:[display="", htmlTag=""]
-++ListView textSize:16.00 style:0 bundle:[aria-disabled="true", display="block", htmlTag="div", onclick="console.log('hi')", role="listbox"]
-++++View textSize:16.00 style:0 bundle:[aria-disabled="true", aria-selected="false", display="block", htmlTag="div", role="option", tabindex="-1"]
-++++++TextView text:"Orange" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-disabled="true", aria-selected="true", display="block", htmlTag="div", role="option", tabindex="-1"]
-++++++TextView text:"Striped" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-disabled="true", aria-selected="false", display="block", htmlTag="div", role="option", tabindex="-1"]
-++++++TextView text:"Calico" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-disabled="true", aria-selected="false", display="block", htmlTag="div", role="option", tabindex="-1"]
-++++++TextView text:"Black" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"End of test" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:32.0 style:1 htmlInfo:[{htmlTag="h1"}, {display="block"}]
+++++TextView text:"Start of test: striped should have selected state" textSize:32.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-disabled="true"}, {onclick="console.log('hi')"}, {role="listbox"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-disabled="true"}, {aria-selected="false"}, {role="option"}, {tabindex="-1"}]
+++++++TextView text:"Orange" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-disabled="true"}, {aria-selected="true"}, {role="option"}, {tabindex="-1"}]
+++++++TextView text:"Striped" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-disabled="true"}, {aria-selected="false"}, {role="option"}, {tabindex="-1"}]
+++++++TextView text:"Calico" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-disabled="true"}, {aria-selected="false"}, {role="option"}, {tabindex="-1"}]
+++++++TextView text:"Black" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"End of test" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-listbox-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-listbox-expected-android-assist-data.txt
index b225c40..99e86a3 100644
--- a/content/test/data/accessibility/aria/aria-listbox-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-listbox-expected-android-assist-data.txt
@@ -1,11 +1,11 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", onclick="console.log('hi')", role="listbox"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="option", tabindex="0"]
-++++++TextView text:"Item 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="option", tabindex="1"]
-++++++TextView text:"Item 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="separator"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="option", tabindex="2"]
-++++++TextView text:"Second group item 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="option", tabindex="3"]
-++++++TextView text:"Second group item 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {onclick="console.log('hi')"}, {role="listbox"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="option"}, {tabindex="0"}]
+++++++TextView text:"Item 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="option"}, {tabindex="1"}]
+++++++TextView text:"Item 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="separator"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="option"}, {tabindex="2"}]
+++++++TextView text:"Second group item 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="option"}, {tabindex="3"}]
+++++++TextView text:"Second group item 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-listitem-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-listitem-expected-android-assist-data.txt
index 46a06d3..bdb7bf92 100644
--- a/content/test/data/accessibility/aria/aria-listitem-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-listitem-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="list"]
-++++View text:"1" textSize:16.00 style:0 bundle:[aria-label="1", display="block", htmlTag="div", role="listitem"]
-++++++TextView text:"Item 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View text:"2" textSize:16.00 style:0 bundle:[aria-label="2", display="block", htmlTag="div", role="listitem"]
-++++++TextView text:"Item 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="list"}]
+++++View text:"1" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="1"}, {role="listitem"}]
+++++++TextView text:"Item 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View text:"2" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="2"}, {role="listitem"}]
+++++++TextView text:"Item 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-live-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-live-expected-android-assist-data.txt
index 8772570538..a3a098f 100644
--- a/content/test/data/accessibility/aria/aria-live-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-live-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[aria-live="off", display="block", htmlTag="div", role="marquee", tabindex="0"]
-++View textSize:16.00 style:0 bundle:[aria-live="polite", display="block", htmlTag="div", role="marquee", tabindex="1"]
-++View textSize:16.00 style:0 bundle:[aria-live="assertive", display="block", htmlTag="div", role="marquee", tabindex="2"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="alert", tabindex="3"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-live="off"}, {role="marquee"}, {tabindex="0"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-live="polite"}, {role="marquee"}, {tabindex="1"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-live="assertive"}, {role="marquee"}, {tabindex="2"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="alert"}, {tabindex="3"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-live-with-content-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-live-with-content-expected-android-assist-data.txt
index 37f8732..5e26d47 100644
--- a/content/test/data/accessibility/aria/aria-live-with-content-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-live-with-content-expected-android-assist-data.txt
@@ -1,7 +1,7 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[aria-live="off", display="block", htmlTag="div", role="marquee"]
-++++TextView text:"Off" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-live="polite", display="block", htmlTag="div", role="marquee"]
-++++TextView text:"Polite" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-live="assertive", display="block", htmlTag="div", role="marquee"]
-++++TextView text:"Assertive" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-live="off"}, {role="marquee"}]
+++++TextView text:"Off" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-live="polite"}, {role="marquee"}]
+++++TextView text:"Polite" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-live="assertive"}, {role="marquee"}]
+++++TextView text:"Assertive" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-log-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-log-expected-android-assist-data.txt
index 7de870e..1f3f8fb 100644
--- a/content/test/data/accessibility/aria/aria-log-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-log-expected-android-assist-data.txt
@@ -1,2 +1,2 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="log"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="log"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-main-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-main-expected-android-assist-data.txt
index 1ad6e50..f8c1c98 100644
--- a/content/test/data/accessibility/aria/aria-main-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-main-expected-android-assist-data.txt
@@ -1,2 +1,2 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="main"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="main"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-marquee-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-marquee-expected-android-assist-data.txt
index c927f360..e56896b 100644
--- a/content/test/data/accessibility/aria/aria-marquee-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-marquee-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[aria-live="off", display="block", htmlTag="div", role="marquee", tabindex="0"]
-++View textSize:16.00 style:0 bundle:[aria-live="polite", display="block", htmlTag="div", role="marquee", tabindex="1"]
-++View textSize:16.00 style:0 bundle:[aria-live="assertive", display="block", htmlTag="div", role="marquee", tabindex="2"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-live="off"}, {role="marquee"}, {tabindex="0"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-live="polite"}, {role="marquee"}, {tabindex="1"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-live="assertive"}, {role="marquee"}, {tabindex="2"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-math-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-math-expected-android-assist-data.txt
index 64751ec..a35f2e9 100644
--- a/content/test/data/accessibility/aria/aria-math-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-math-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="math"]
-++++TextView text:"ARIA role math." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="math"}]
+++++TextView text:"ARIA role math." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-menu-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-menu-expected-android-assist-data.txt
index 3a686ea..e380b93 100644
--- a/content/test/data/accessibility/aria/aria-menu-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-menu-expected-android-assist-data.txt
@@ -1,17 +1,17 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", role="menubar", style="list-style-type: none"]
-++++MenuItem textSize:16.00 style:0 bundle:[aria-controls="filemenu", display="list-item", htmlTag="li", role="menuitem"]
-++++++TextView text:"File" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++MenuItem textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", role="menuitem"]
-++++++TextView text:"Edit" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++MenuItem textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", role="menuitem"]
-++++++TextView text:"View" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"File" textSize:16.00 style:0 bundle:[aria-label="File", display="block", htmlTag="ul", id="filemenu", role="menu", style="list-style-type: none"]
-++++MenuItem textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", role="menuitem"]
-++++++TextView text:"New" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++MenuItem textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", role="menuitem"]
-++++++TextView text:"Open" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++MenuItem textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", role="menuitem"]
-++++++TextView text:"Save" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++MenuItem textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", role="menuitem"]
-++++++TextView text:"Quit" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {role="menubar"}, {style="list-style-type: none"}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-controls="filemenu"}, {role="menuitem"}]
+++++++TextView text:"File" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {role="menuitem"}]
+++++++TextView text:"Edit" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {role="menuitem"}]
+++++++TextView text:"View" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"File" textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {aria-label="File"}, {id="filemenu"}, {role="menu"}, {style="list-style-type: none"}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {role="menuitem"}]
+++++++TextView text:"New" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {role="menuitem"}]
+++++++TextView text:"Open" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {role="menuitem"}]
+++++++TextView text:"Save" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {role="menuitem"}]
+++++++TextView text:"Quit" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-menubar-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-menubar-expected-android-assist-data.txt
index 826264d..926d1587 100644
--- a/content/test/data/accessibility/aria/aria-menubar-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-menubar-expected-android-assist-data.txt
@@ -1,8 +1,8 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", role="menubar", style="list-style-type: none"]
-++++MenuItem textSize:16.00 style:0 bundle:[aria-controls="filemenu", display="list-item", htmlTag="li", role="menuitem"]
-++++++TextView text:"File" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++MenuItem textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", role="menuitem"]
-++++++TextView text:"Edit" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++MenuItem textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", role="menuitem"]
-++++++TextView text:"View" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {role="menubar"}, {style="list-style-type: none"}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-controls="filemenu"}, {role="menuitem"}]
+++++++TextView text:"File" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {role="menuitem"}]
+++++++TextView text:"Edit" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {role="menuitem"}]
+++++++TextView text:"View" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-menuitem-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-menuitem-expected-android-assist-data.txt
index 7e72d76..3422726 100644
--- a/content/test/data/accessibility/aria/aria-menuitem-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-menuitem-expected-android-assist-data.txt
@@ -1,11 +1,11 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="menu"]
-++++MenuItem textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="menuitem", tabindex="0"]
-++++++TextView text:"File" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++MenuItem textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="menuitem", tabindex="1"]
-++++++TextView text:"Edit" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++MenuItem textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="menuitem", tabindex="2"]
-++++++TextView text:"Complex " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++EditText textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input"]
-++++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++++TextView text:" menuitem" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="menu"}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="menuitem"}, {tabindex="0"}]
+++++++TextView text:"File" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="menuitem"}, {tabindex="1"}]
+++++++TextView text:"Edit" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="menuitem"}, {tabindex="2"}]
+++++++TextView text:"Complex " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}]
+++++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++++TextView text:" menuitem" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-menuitem-in-group-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-menuitem-in-group-expected-android-assist-data.txt
index bb0c206..164231a 100644
--- a/content/test/data/accessibility/aria/aria-menuitem-in-group-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-menuitem-in-group-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="group"]
-++++MenuItem textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="menuitem", tabindex="0"]
-++++++TextView text:"Menu item" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="group"}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="menuitem"}, {tabindex="0"}]
+++++++TextView text:"Menu item" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-menuitemcheckbox-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-menuitemcheckbox-expected-android-assist-data.txt
index 3ff6c993..5551906 100644
--- a/content/test/data/accessibility/aria/aria-menuitemcheckbox-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-menuitemcheckbox-expected-android-assist-data.txt
@@ -1,8 +1,8 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="menu"]
-++++MenuItem textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="menuitemcheckbox"]
-++++++TextView text:"Menu item 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++MenuItem textSize:16.00 style:0 bundle:[aria-checked="true", display="block", htmlTag="div", role="menuitemcheckbox"]
-++++++TextView text:"Menu item 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++MenuItem textSize:16.00 style:0 bundle:[aria-checked="mixed", display="block", htmlTag="div", role="menuitemcheckbox"]
-++++++TextView text:"Menu item 3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="menu"}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="menuitemcheckbox"}]
+++++++TextView text:"Menu item 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-checked="true"}, {role="menuitemcheckbox"}]
+++++++TextView text:"Menu item 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-checked="mixed"}, {role="menuitemcheckbox"}]
+++++++TextView text:"Menu item 3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-menuitemradio-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-menuitemradio-expected-android-assist-data.txt
index b2a8353..133f037 100644
--- a/content/test/data/accessibility/aria/aria-menuitemradio-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-menuitemradio-expected-android-assist-data.txt
@@ -1,8 +1,8 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="menu"]
-++++MenuItem textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="menuitemradio"]
-++++++TextView text:"Menu item 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++MenuItem textSize:16.00 style:0 bundle:[aria-checked="true", display="block", htmlTag="div", role="menuitemradio"]
-++++++TextView text:"Menu item 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++MenuItem textSize:16.00 style:0 bundle:[aria-checked="mixed", display="block", htmlTag="div", role="menuitemradio"]
-++++++TextView text:"Menu item 3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="menu"}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="menuitemradio"}]
+++++++TextView text:"Menu item 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-checked="true"}, {role="menuitemradio"}]
+++++++TextView text:"Menu item 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-checked="mixed"}, {role="menuitemradio"}]
+++++++TextView text:"Menu item 3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-meter-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-meter-expected-android-assist-data.txt
index ca0ea5e..1785c85 100644
--- a/content/test/data/accessibility/aria/aria-meter-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-meter-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ProgressBar text:"funding" textSize:16.00 style:0 bundle:[aria-label="funding", aria-valuemax="100", aria-valuemin="0", aria-valuenow="50", aria-valuetext="half-way", display="block", htmlTag="div", role="meter"]
-++++TextView text:"We're getting there!" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ProgressBar text:"funding" textSize:16.00 style:0 bundle:[aria-label="funding", aria-valuemax="100", aria-valuemin="0", aria-valuenow="10", display="block", htmlTag="div", role="meter"]
-++++TextView text:"Not so great." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ProgressBar text:"funding" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="funding"}, {aria-valuemax="100"}, {aria-valuemin="0"}, {aria-valuenow="50"}, {aria-valuetext="half-way"}, {role="meter"}]
+++++TextView text:"We're getting there!" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ProgressBar text:"funding" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="funding"}, {aria-valuemax="100"}, {aria-valuemin="0"}, {aria-valuenow="10"}, {role="meter"}]
+++++TextView text:"Not so great." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-mismatched-table-attr-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-mismatched-table-attr-expected-android-assist-data.txt
index ebc4181e..6e148af 100644
--- a/content/test/data/accessibility/aria/aria-mismatched-table-attr-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-mismatched-table-attr-expected-android-assist-data.txt
@@ -1,19 +1,19 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++GridView textSize:16.00 style:0 bundle:[aria-colcount="1", aria-rowcount="1", display="table", htmlTag="table", role="grid"]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:1 bundle:[aria-colindex="1", aria-rowindex="1", display="table-cell", htmlTag="th"]
-++++++++TextView text:"Column 1" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:1 bundle:[aria-colindex="2", aria-rowindex="1", display="table-cell", htmlTag="th"]
-++++++++TextView text:"Column 2" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:1 bundle:[aria-colindex="2", aria-rowindex="1", display="table-cell", htmlTag="th"]
-++++++++TextView text:"Column 3" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[aria-colindex="2", aria-rowindex="2", display="table-cell", htmlTag="td", role="gridcell", tabindex="0"]
-++++++++TextView text:"Cell A2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[aria-colindex="1", aria-rowindex="2", display="table-cell", htmlTag="td", role="gridcell", tabindex="-1"]
-++++++++TextView text:"Cell A3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[aria-colindex="1", aria-rowindex="2", display="table-cell", htmlTag="td", role="gridcell", tabindex="0"]
-++++++++TextView text:"Cell B1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[aria-colindex="2", aria-rowindex="2", display="table-cell", htmlTag="td", role="gridcell", tabindex="-1"]
-++++++++TextView text:"Cell B2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}, {aria-colcount="1"}, {aria-rowcount="1"}, {role="grid"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}, {aria-colindex="1"}, {aria-rowindex="1"}]
+++++++++TextView text:"Column 1" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}, {aria-colindex="2"}, {aria-rowindex="1"}]
+++++++++TextView text:"Column 2" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}, {aria-colindex="2"}, {aria-rowindex="1"}]
+++++++++TextView text:"Column 3" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {aria-colindex="2"}, {aria-rowindex="2"}, {role="gridcell"}, {tabindex="0"}]
+++++++++TextView text:"Cell A2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {aria-colindex="1"}, {aria-rowindex="2"}, {role="gridcell"}, {tabindex="-1"}]
+++++++++TextView text:"Cell A3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {aria-colindex="1"}, {aria-rowindex="2"}, {role="gridcell"}, {tabindex="0"}]
+++++++++TextView text:"Cell B1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {aria-colindex="2"}, {aria-rowindex="2"}, {role="gridcell"}, {tabindex="-1"}]
+++++++++TextView text:"Cell B2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-multiline-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-multiline-expected-android-assist-data.txt
index cbde057..3a812a1 100644
--- a/content/test/data/accessibility/aria/aria-multiline-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-multiline-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++EditText textSize:16.00 style:0 bundle:[aria-multiline="false", display="block", htmlTag="div", role="textbox"]
-++EditText textSize:16.00 style:0 bundle:[aria-multiline="true", display="block", htmlTag="div", role="textbox"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++EditText textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-multiline="false"}, {role="textbox"}]
+++EditText textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-multiline="true"}, {role="textbox"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-multiselectable-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-multiselectable-expected-android-assist-data.txt
index 91fca476..6f641ff 100644
--- a/content/test/data/accessibility/aria/aria-multiselectable-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-multiselectable-expected-android-assist-data.txt
@@ -1,27 +1,27 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ListView text:"My Listbox" textSize:16.00 style:0 bundle:[aria-label="My Listbox", aria-multiselectable="true", display="block", htmlTag="ul", onclick="console.log('hi')", role="listbox", tabindex="0"]
-++++View textSize:16.00 style:0 bundle:[aria-selected="false", display="list-item", htmlTag="li", role="option"]
-++++++TextView text:"• " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"Example 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-selected="false", display="list-item", htmlTag="li", role="option"]
-++++++TextView text:"• " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"Example 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-selected="false", display="list-item", htmlTag="li", role="option"]
-++++++TextView text:"• " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"Example 3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-selected="false", display="list-item", htmlTag="li", role="option"]
-++++++TextView text:"• " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"Example 4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ListView text:"My Listbox" textSize:16.00 style:0 bundle:[aria-label="My Listbox", aria-multiselectable="true", display="block", htmlTag="ul", onclick="console.log('hi')", role="listbox", tabindex="0"]
-++++View textSize:16.00 style:0 bundle:[aria-selected="false", display="list-item", htmlTag="li", role="option"]
-++++++TextView text:"• " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"Example 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-selected="true", display="list-item", htmlTag="li", role="option"]
-++++++TextView text:"• " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"Example 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-selected="false", display="list-item", htmlTag="li", role="option"]
-++++++TextView text:"• " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"Example 3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-selected="true", display="list-item", htmlTag="li", role="option"]
-++++++TextView text:"• " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"Example 4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ListView text:"My Listbox" textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {aria-label="My Listbox"}, {aria-multiselectable="true"}, {onclick="console.log('hi')"}, {role="listbox"}, {tabindex="0"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-selected="false"}, {role="option"}]
+++++++TextView text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"Example 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-selected="false"}, {role="option"}]
+++++++TextView text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"Example 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-selected="false"}, {role="option"}]
+++++++TextView text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"Example 3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-selected="false"}, {role="option"}]
+++++++TextView text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"Example 4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ListView text:"My Listbox" textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {aria-label="My Listbox"}, {aria-multiselectable="true"}, {onclick="console.log('hi')"}, {role="listbox"}, {tabindex="0"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-selected="false"}, {role="option"}]
+++++++TextView text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"Example 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-selected="true"}, {role="option"}]
+++++++TextView text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"Example 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-selected="false"}, {role="option"}]
+++++++TextView text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"Example 3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-selected="true"}, {role="option"}]
+++++++TextView text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"Example 4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-navigation-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-navigation-expected-android-assist-data.txt
index b30fa74..84412b9 100644
--- a/content/test/data/accessibility/aria/aria-navigation-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-navigation-expected-android-assist-data.txt
@@ -1,2 +1,2 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="navigation"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="navigation"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-none-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-none-expected-android-assist-data.txt
index 4e3637fc..5baa511 100644
--- a/content/test/data/accessibility/aria/aria-none-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-none-expected-android-assist-data.txt
@@ -1,2 +1,2 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++TextView text:"With aria-role none" textSize:32.00 style:1 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++TextView text:"With aria-role none" textSize:32.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-note-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-note-expected-android-assist-data.txt
index a0071ef93..731181e 100644
--- a/content/test/data/accessibility/aria/aria-note-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-note-expected-android-assist-data.txt
@@ -1,2 +1,2 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="note"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="note"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-option-complex-children-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-option-complex-children-expected-android-assist-data.txt
index 1e655295..71e9b2c 100644
--- a/content/test/data/accessibility/aria/aria-option-complex-children-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-option-complex-children-expected-android-assist-data.txt
@@ -1,13 +1,13 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ListView textSize:16.00 style:0 bundle:[aria-activedescendant="opt1", display="block", htmlTag="div", role="listbox"]
-++++View text:"label-WAI-ARIA 1.1" textSize:16.00 style:0 bundle:[aria-label="label-WAI-ARIA 1.1", aria-selected="true", display="block", htmlTag="div", id="opt1", role="option"]
-++++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="https://www.w3.org/TR/wai-aria-practices-1.1/", htmlTag="a", tabindex="-1", title="title-WAI-ARIA 1.1"]
-++++++++TextView text:"href-WAI-ARIA 1.1" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++++View text:"title-https://www.w3.org/TR/wai-aria-practices-1.1/" textSize:16.00 style:0 bundle:[display="block", htmlTag="p", title="title-https://www.w3.org/TR/wai-aria-practices-1.1/"]
-++++++++TextView text:"link-https://www.w3.org/TR/wai-aria-practices-1.1/" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="button"]
-++++++++TextView text:"Close" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++++View text:"1234567" textSize:16.00 style:0 bundle:[aria-label="1234567", display="block", htmlTag="div", id="opt2", role="option"]
-++++++TextView text:"href-WAI-ARIA 1.1 " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="button"]
-++++++++TextView text:"Close" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-activedescendant="opt1"}, {role="listbox"}]
+++++View text:"label-WAI-ARIA 1.1" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="label-WAI-ARIA 1.1"}, {aria-selected="true"}, {id="opt1"}, {role="option"}]
+++++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="https://www.w3.org/TR/wai-aria-practices-1.1/"}, {tabindex="-1"}, {title="title-WAI-ARIA 1.1"}]
+++++++++TextView text:"href-WAI-ARIA 1.1" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View text:"title-https://www.w3.org/TR/wai-aria-practices-1.1/" textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {title="title-https://www.w3.org/TR/wai-aria-practices-1.1/"}]
+++++++++TextView text:"link-https://www.w3.org/TR/wai-aria-practices-1.1/" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}]
+++++++++TextView text:"Close" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View text:"1234567" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="1234567"}, {id="opt2"}, {role="option"}]
+++++++TextView text:"href-WAI-ARIA 1.1 " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}]
+++++++++TextView text:"Close" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-option-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-option-expected-android-assist-data.txt
index 815ca7f..e1e5c6cd 100644
--- a/content/test/data/accessibility/aria/aria-option-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-option-expected-android-assist-data.txt
@@ -1,15 +1,15 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ListView textSize:16.00 style:0 bundle:[aria-activedescendant="opt1", display="block", htmlTag="div", onclick="console.log('hi')", role="listbox"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="opt1", role="option"]
-++++++TextView text:"option 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View text:"label 2" textSize:16.00 style:0 bundle:[aria-label="label 2", display="block", htmlTag="div", id="opt2", role="option"]
-++++++TextView text:"option 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="opt3", role="option"]
-++++++TextView text:"cat" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"erpillar" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="opt4", role="option"]
-++++++TextView text:"cat" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"fish" textSize:16.00 style:2 bundle:[display="", htmlTag=""]
-++++View text:"medusa" textSize:16.00 style:0 bundle:[aria-label="medusa", display="block", htmlTag="div", id="opt5", role="option"]
-++++++TextView text:"jelly" textSize:16.00 style:2 bundle:[display="", htmlTag=""]
-++++++TextView text:"fish" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-activedescendant="opt1"}, {onclick="console.log('hi')"}, {role="listbox"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="opt1"}, {role="option"}]
+++++++TextView text:"option 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View text:"label 2" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="label 2"}, {id="opt2"}, {role="option"}]
+++++++TextView text:"option 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="opt3"}, {role="option"}]
+++++++TextView text:"cat" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"erpillar" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="opt4"}, {role="option"}]
+++++++TextView text:"cat" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"fish" textSize:16.0 style:2 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View text:"medusa" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="medusa"}, {id="opt5"}, {role="option"}]
+++++++TextView text:"jelly" textSize:16.0 style:2 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"fish" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-orientation-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-orientation-expected-android-assist-data.txt
index 5a04b5b..db112cd 100644
--- a/content/test/data/accessibility/aria/aria-orientation-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-orientation-expected-android-assist-data.txt
@@ -1,37 +1,37 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="combobox"]
-++View textSize:16.00 style:0 bundle:[aria-orientation="horizontal", display="block", htmlTag="div", role="combobox"]
-++View textSize:16.00 style:0 bundle:[aria-orientation="vertical", display="block", htmlTag="div", role="combobox"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="listbox"]
-++ListView textSize:16.00 style:0 bundle:[aria-orientation="horizontal", display="block", htmlTag="div", role="listbox"]
-++ListView textSize:16.00 style:0 bundle:[aria-orientation="vertical", display="block", htmlTag="div", role="listbox"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="menu"]
-++View textSize:16.00 style:0 bundle:[aria-orientation="horizontal", display="block", htmlTag="div", role="menu"]
-++View textSize:16.00 style:0 bundle:[aria-orientation="vertical", display="block", htmlTag="div", role="menu"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="menubar"]
-++View textSize:16.00 style:0 bundle:[aria-orientation="horizontal", display="block", htmlTag="div", role="menubar"]
-++View textSize:16.00 style:0 bundle:[aria-orientation="vertical", display="block", htmlTag="div", role="menubar"]
-++RadioGroup textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="radiogroup"]
-++RadioGroup textSize:16.00 style:0 bundle:[aria-orientation="horizontal", display="block", htmlTag="div", role="radiogroup"]
-++RadioGroup textSize:16.00 style:0 bundle:[aria-orientation="vertical", display="block", htmlTag="div", role="radiogroup"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="scrollbar"]
-++View textSize:16.00 style:0 bundle:[aria-orientation="horizontal", display="block", htmlTag="div", role="scrollbar"]
-++View textSize:16.00 style:0 bundle:[aria-orientation="vertical", display="block", htmlTag="div", role="scrollbar"]
-++SeekBar textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="slider"]
-++SeekBar textSize:16.00 style:0 bundle:[aria-orientation="horizontal", display="block", htmlTag="div", role="slider"]
-++SeekBar textSize:16.00 style:0 bundle:[aria-orientation="vertical", display="block", htmlTag="div", role="slider"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="separator"]
-++View textSize:16.00 style:0 bundle:[aria-orientation="horizontal", display="block", htmlTag="div", role="separator"]
-++View textSize:16.00 style:0 bundle:[aria-orientation="vertical", display="block", htmlTag="div", role="separator"]
-++TabWidget textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="tablist"]
-++TabWidget textSize:16.00 style:0 bundle:[aria-orientation="horizontal", display="block", htmlTag="div", role="tablist"]
-++TabWidget textSize:16.00 style:0 bundle:[aria-orientation="vertical", display="block", htmlTag="div", role="tablist"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="toolbar"]
-++View textSize:16.00 style:0 bundle:[aria-orientation="horizontal", display="block", htmlTag="div", role="toolbar"]
-++View textSize:16.00 style:0 bundle:[aria-orientation="vertical", display="block", htmlTag="div", role="toolbar"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="tree"]
-++View textSize:16.00 style:0 bundle:[aria-orientation="horizontal", display="block", htmlTag="div", role="tree"]
-++View textSize:16.00 style:0 bundle:[aria-orientation="vertical", display="block", htmlTag="div", role="tree"]
-++GridView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="treegrid"]
-++GridView textSize:16.00 style:0 bundle:[aria-orientation="horizontal", display="block", htmlTag="div", role="treegrid"]
-++GridView textSize:16.00 style:0 bundle:[aria-orientation="vertical", display="block", htmlTag="div", role="treegrid"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="combobox"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-orientation="horizontal"}, {role="combobox"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-orientation="vertical"}, {role="combobox"}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="listbox"}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-orientation="horizontal"}, {role="listbox"}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-orientation="vertical"}, {role="listbox"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="menu"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-orientation="horizontal"}, {role="menu"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-orientation="vertical"}, {role="menu"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="menubar"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-orientation="horizontal"}, {role="menubar"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-orientation="vertical"}, {role="menubar"}]
+++RadioGroup textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="radiogroup"}]
+++RadioGroup textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-orientation="horizontal"}, {role="radiogroup"}]
+++RadioGroup textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-orientation="vertical"}, {role="radiogroup"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="scrollbar"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-orientation="horizontal"}, {role="scrollbar"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-orientation="vertical"}, {role="scrollbar"}]
+++SeekBar textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="slider"}]
+++SeekBar textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-orientation="horizontal"}, {role="slider"}]
+++SeekBar textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-orientation="vertical"}, {role="slider"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="separator"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-orientation="horizontal"}, {role="separator"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-orientation="vertical"}, {role="separator"}]
+++TabWidget textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="tablist"}]
+++TabWidget textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-orientation="horizontal"}, {role="tablist"}]
+++TabWidget textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-orientation="vertical"}, {role="tablist"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="toolbar"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-orientation="horizontal"}, {role="toolbar"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-orientation="vertical"}, {role="toolbar"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="tree"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-orientation="horizontal"}, {role="tree"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-orientation="vertical"}, {role="tree"}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="treegrid"}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-orientation="horizontal"}, {role="treegrid"}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-orientation="vertical"}, {role="treegrid"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-owns-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-owns-expected-android-assist-data.txt
index 90b2b71..3856b26 100644
--- a/content/test/data/accessibility/aria/aria-owns-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-owns-expected-android-assist-data.txt
@@ -1,17 +1,17 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ListView textSize:16.00 style:0 bundle:[aria-owns="two four", display="block", htmlTag="ul"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"• " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++++++TextView text:"One" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", id="two"]
-++++++View text:"•" textSize:16.00 style:0 bundle:[display="inline", htmlTag="::marker"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++++++TextView text:"Two" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", id="four"]
-++++++View text:"• " textSize:16.00 style:0 bundle:[display="inline", htmlTag="::marker"]
-++++++TextView text:"Four" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", id="three"]
-++++View text:"•" textSize:16.00 style:0 bundle:[display="inline", htmlTag="::marker"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++++TextView text:"Three" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {aria-owns="two four"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++++++TextView text:"One" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {id="two"}]
+++++++View text:"•" textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++++++TextView text:"Two" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {id="four"}]
+++++++View text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline"}]
+++++++TextView text:"Four" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {id="three"}]
+++++View text:"•" textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++++TextView text:"Three" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-owns-from-display-none-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-owns-from-display-none-expected-android-assist-data.txt
index c268ed0..3bd859a 100644
--- a/content/test/data/accessibility/aria/aria-owns-from-display-none-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-owns-from-display-none-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++EditText textSize:13.33 style:0 bundle:[display="block", htmlTag="textarea", id="input-0"]
-++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="textarea"}, {display="block"}, {id="input-0"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-owns-ignored-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-owns-ignored-expected-android-assist-data.txt
index 31f1de1..e504c748 100644
--- a/content/test/data/accessibility/aria/aria-owns-ignored-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-owns-ignored-expected-android-assist-data.txt
@@ -1,16 +1,16 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View text:"Ordinary presentation element with id" textSize:16.00 style:0 bundle:[aria-label="Ordinary presentation element with id", display="block", htmlTag="hr"]
-++View text:"An aria-owned element is never ignored" textSize:16.00 style:0 bundle:[aria-label="An aria-owned element is never ignored", display="block", htmlTag="hr"]
-++View textSize:16.00 style:0 bundle:[aria-owns="presentational1", display="block", htmlTag="div", role="group"]
-++++Button text:"button-in-owned-tree" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="input", type="button", value="button-in-owned-tree"]
-++++++TextView text:"button-in-owned-tree" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++View text:"Element with aria-owns is never ignored" textSize:16.00 style:0 bundle:[aria-label="Element with aria-owns is never ignored", display="block", htmlTag="hr"]
-++View textSize:16.00 style:0 bundle:[aria-owns="textbox", display="block", htmlTag="div", role="presentation"]
-++++EditText textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", id="textbox", type="text"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++View text:"Owning an element with an ignored parent serializes cleanly" textSize:16.00 style:0 bundle:[aria-label="Owning an element with an ignored parent serializes cleanly", display="block", htmlTag="hr"]
-++View textSize:16.00 style:0 bundle:[aria-owns="checkbox", display="block", htmlTag="div", role="group"]
-++++CheckBox textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", id="checkbox", type="checkbox"]
-++View text:"All the above in one" textSize:16.00 style:0 bundle:[aria-label="All the above in one", display="block", htmlTag="hr"]
-++View textSize:16.00 style:0 bundle:[aria-owns="presentational3", display="block", htmlTag="div", role="presentation"]
-++++SeekBar textSize:13.33 style:0 fgColor:-6449522 bundle:[display="inline-block", htmlTag="input", id="range", type="range"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View text:"Ordinary presentation element with id" textSize:16.0 style:0 htmlInfo:[{htmlTag="hr"}, {display="block"}, {aria-label="Ordinary presentation element with id"}]
+++View text:"An aria-owned element is never ignored" textSize:16.0 style:0 htmlInfo:[{htmlTag="hr"}, {display="block"}, {aria-label="An aria-owned element is never ignored"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-owns="presentational1"}, {role="group"}]
+++++Button text:"button-in-owned-tree" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="button"}, {value="button-in-owned-tree"}]
+++++++TextView text:"button-in-owned-tree" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"Element with aria-owns is never ignored" textSize:16.0 style:0 htmlInfo:[{htmlTag="hr"}, {display="block"}, {aria-label="Element with aria-owns is never ignored"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-owns="textbox"}, {role="presentation"}]
+++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {id="textbox"}, {type="text"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++View text:"Owning an element with an ignored parent serializes cleanly" textSize:16.0 style:0 htmlInfo:[{htmlTag="hr"}, {display="block"}, {aria-label="Owning an element with an ignored parent serializes cleanly"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-owns="checkbox"}, {role="group"}]
+++++CheckBox textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {id="checkbox"}, {type="checkbox"}]
+++View text:"All the above in one" textSize:16.0 style:0 htmlInfo:[{htmlTag="hr"}, {display="block"}, {aria-label="All the above in one"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-owns="presentational3"}, {role="presentation"}]
+++++SeekBar textSize:13.3 style:0 fgColor:-6449522 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {id="range"}, {type="range"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-owns-list-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-owns-list-expected-android-assist-data.txt
index 3b523bb..ac271b7 100644
--- a/content/test/data/accessibility/aria/aria-owns-list-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-owns-list-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ListView textSize:16.00 style:0 bundle:[aria-owns="one two", display="block", htmlTag="div", role="list"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="one", role="listitem"]
-++++++TextView text:"One" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="two", role="listitem"]
-++++++TextView text:"Two" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-owns="one two"}, {role="list"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="one"}, {role="listitem"}]
+++++++TextView text:"One" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="two"}, {role="listitem"}]
+++++++TextView text:"Two" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-presentation-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-presentation-expected-android-assist-data.txt
index a36bdf8..7b7c6579 100644
--- a/content/test/data/accessibility/aria/aria-presentation-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-presentation-expected-android-assist-data.txt
@@ -1,2 +1,2 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++TextView text:"aria-role presentation" textSize:32.00 style:1 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++TextView text:"aria-role presentation" textSize:32.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-presentation-in-list-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-presentation-in-list-expected-android-assist-data.txt
index 0b6923f..8792ef81 100644
--- a/content/test/data/accessibility/aria/aria-presentation-in-list-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-presentation-in-list-expected-android-assist-data.txt
@@ -1,10 +1,10 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"• " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"One" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"• " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"Two" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"Three" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"One" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"Two" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"Three" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-pressed-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-pressed-expected-android-assist-data.txt
index 29b63ecb..3ec4a34 100644
--- a/content/test/data/accessibility/aria/aria-pressed-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-pressed-expected-android-assist-data.txt
@@ -1,9 +1,9 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++Button textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="button", tabindex="0"]
-++++TextView text:"Regular button" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ToggleButton textSize:16.00 style:0 bundle:[aria-pressed="false", display="block", htmlTag="div", role="button", tabindex="1"]
-++++TextView text:"Toggle button unpressed" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ToggleButton textSize:16.00 style:0 bundle:[aria-pressed="true", display="block", htmlTag="div", role="button", tabindex="2"]
-++++TextView text:"Toggle button pressed" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ToggleButton textSize:16.00 style:0 bundle:[aria-pressed="mixed", display="block", htmlTag="div", role="button", tabindex="3"]
-++++TextView text:"Toggle button mixed" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++Button textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="button"}, {tabindex="0"}]
+++++TextView text:"Regular button" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ToggleButton textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-pressed="false"}, {role="button"}, {tabindex="1"}]
+++++TextView text:"Toggle button unpressed" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ToggleButton textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-pressed="true"}, {role="button"}, {tabindex="2"}]
+++++TextView text:"Toggle button pressed" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ToggleButton textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-pressed="mixed"}, {role="button"}, {tabindex="3"}]
+++++TextView text:"Toggle button mixed" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-progressbar-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-progressbar-expected-android-assist-data.txt
index 6f62cde48..bd0ff346 100644
--- a/content/test/data/accessibility/aria/aria-progressbar-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-progressbar-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ProgressBar textSize:16.00 style:0 bundle:[aria-valuemax="37", aria-valuemin="1", aria-valuenow="3", display="block", htmlTag="div", role="progressbar"]
-++ProgressBar text:"three" textSize:16.00 style:0 bundle:[aria-valuemax="96", aria-valuemin="1", aria-valuenow="3", aria-valuetext="three", display="block", htmlTag="div", role="progressbar"]
-++ProgressBar textSize:16.00 style:0 bundle:[aria-valuemax="10", aria-valuemin="0", display="block", htmlTag="div", role="progressbar"]
-++ProgressBar textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="progressbar"]
-++ProgressBar text:"Test label" textSize:16.00 style:0 bundle:[aria-label="Test label", aria-valuemax="100", aria-valuemin="0", display="block", htmlTag="div", role="progressbar"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ProgressBar textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-valuemax="37"}, {aria-valuemin="1"}, {aria-valuenow="3"}, {role="progressbar"}]
+++ProgressBar text:"three" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-valuemax="96"}, {aria-valuemin="1"}, {aria-valuenow="3"}, {aria-valuetext="three"}, {role="progressbar"}]
+++ProgressBar textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-valuemax="10"}, {aria-valuemin="0"}, {role="progressbar"}]
+++ProgressBar textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="progressbar"}]
+++ProgressBar text:"Test label" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Test label"}, {aria-valuemax="100"}, {aria-valuemin="0"}, {role="progressbar"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-radio-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-radio-expected-android-assist-data.txt
index b560855..9d74ad0b 100644
--- a/content/test/data/accessibility/aria/aria-radio-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-radio-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++RadioButton textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="radio"]
-++++TextView text:"Radio1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++RadioButton textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="radio"}]
+++++TextView text:"Radio1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-radiogroup-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-radiogroup-expected-android-assist-data.txt
index 07e947e..3344309 100644
--- a/content/test/data/accessibility/aria/aria-radiogroup-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-radiogroup-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++RadioGroup text:"My group" textSize:16.00 style:0 bundle:[aria-label="My group", display="block", htmlTag="div", role="radiogroup"]
-++++RadioButton textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="radio", tabindex="0"]
-++++++TextView text:"Radio 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++RadioButton textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="radio", tabindex="1"]
-++++++TextView text:"Radio 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++RadioGroup text:"My group" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="My group"}, {role="radiogroup"}]
+++++RadioButton textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="radio"}, {tabindex="0"}]
+++++++TextView text:"Radio 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++RadioButton textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="radio"}, {tabindex="1"}]
+++++++TextView text:"Radio 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-readonly-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-readonly-expected-android-assist-data.txt
index c7fe2556..c653dfe 100644
--- a/content/test/data/accessibility/aria/aria-readonly-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-readonly-expected-android-assist-data.txt
@@ -1,33 +1,33 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++EditText text:"Readonly-false input" textSize:13.33 style:0 bundle:[aria-readonly="false", display="inline-block", htmlTag="input", tabindex="0", value="Readonly-false input"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++++++TextView text:"Readonly-false input" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++EditText text:"Readonly-true input" textSize:13.33 style:0 bundle:[aria-readonly="true", display="inline-block", htmlTag="input", tabindex="0", value="Readonly-true input"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++++++TextView text:"Readonly-true input" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++View text:"Readonly-false plain div" textSize:16.00 style:0 bundle:[aria-label="Readonly-false plain div", aria-readonly="false", display="block", htmlTag="div", tabindex="0"]
-++View text:"Readonly-true plain div" textSize:16.00 style:0 bundle:[aria-label="Readonly-true plain div", aria-readonly="true", display="block", htmlTag="div", tabindex="0"]
-++View text:"Readonly-false contenteditable div" textSize:16.00 style:0 bundle:[aria-label="Readonly-false contenteditable div", aria-readonly="false", contenteditable="", display="block", htmlTag="div", tabindex="0"]
-++View text:"Readonly-true contenteditable div" textSize:16.00 style:0 bundle:[aria-label="Readonly-true contenteditable div", aria-readonly="true", contenteditable="", display="block", htmlTag="div", tabindex="0"]
-++EditText text:"Readonly-false role unimplemented textbox" textSize:16.00 style:0 bundle:[aria-label="Readonly-false role unimplemented textbox", aria-readonly="false", display="block", htmlTag="div", role="textbox", tabindex="0"]
-++EditText text:"Readonly-true role unimplemented textbox" textSize:16.00 style:0 bundle:[aria-label="Readonly-true role unimplemented textbox", aria-readonly="true", display="block", htmlTag="div", role="textbox", tabindex="0"]
-++EditText text:"Readonly-false contenteditable textbox" textSize:16.00 style:0 bundle:[aria-label="Readonly-false contenteditable textbox", aria-readonly="false", display="block", htmlTag="div", role="textbox", tabindex="0"]
-++EditText text:"Readonly-true contenteditable textbox" textSize:16.00 style:0 bundle:[aria-label="Readonly-true contenteditable textbox", aria-readonly="true", display="block", htmlTag="div", role="textbox", tabindex="0"]
-++GridView textSize:16.00 style:0 bundle:[display="table", htmlTag="table", role="grid"]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr", role="row"]
-++++++View text:"Readonly-false gridcell" textSize:16.00 style:0 bundle:[aria-label="Readonly-false gridcell", aria-readonly="false", display="table-cell", htmlTag="td", role="gridcell", tabindex="0"]
-++++++View text:"Readonly-true gridcell" textSize:16.00 style:0 bundle:[aria-label="Readonly-true gridcell", aria-readonly="true", display="table-cell", htmlTag="td", role="gridcell", tabindex="0"]
-++++++View text:"Readonly not specified gridcell" textSize:16.00 style:0 bundle:[aria-label="Readonly not specified gridcell", display="table-cell", htmlTag="td", role="gridcell", tabindex="0"]
-++CheckBox text:"Readonly checkbox" textSize:16.00 style:0 bundle:[aria-label="Readonly checkbox", aria-readonly="true", display="block", htmlTag="div", role="checkbox"]
-++EditText text:"Readonly combobox" textSize:13.33 style:0 bundle:[aria-label="Readonly combobox", aria-readonly="true", display="inline-block", htmlTag="input", role="combobox"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++ListView text:"Readonly listbox" textSize:16.00 style:0 bundle:[aria-label="Readonly listbox", aria-readonly="true", display="block", htmlTag="div", role="listbox"]
-++RadioGroup text:"Readonly radiogroup" textSize:16.00 style:0 bundle:[aria-label="Readonly radiogroup", aria-readonly="true", display="block", htmlTag="div", role="radiogroup"]
-++SeekBar text:"Readonly slider" textSize:16.00 style:0 bundle:[aria-label="Readonly slider", aria-readonly="true", display="block", htmlTag="div", role="slider"]
-++EditText text:"Readonly spinbutton" textSize:16.00 style:0 bundle:[aria-label="Readonly spinbutton", aria-readonly="true", display="block", htmlTag="div", role="spinbutton"]
-++MenuItem text:"Readonly menuitemcheckbox" textSize:16.00 style:0 bundle:[aria-label="Readonly menuitemcheckbox", aria-readonly="true", display="block", htmlTag="div", role="menuitemcheckbox"]
-++MenuItem text:"Readonly menuitemradio" textSize:16.00 style:0 bundle:[aria-label="Readonly menuitemradio", aria-readonly="true", display="block", htmlTag="div", role="menuitemradio"]
-++EditText text:"Readonly searchbox" textSize:16.00 style:0 bundle:[aria-label="Readonly searchbox", aria-readonly="true", display="block", htmlTag="div", role="searchbox"]
-++ToggleButton text:"Readonly switch" textSize:16.00 style:0 bundle:[aria-label="Readonly switch", aria-readonly="true", display="block", htmlTag="div", role="switch"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++EditText text:"Readonly-false input" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-readonly="false"}, {tabindex="0"}, {value="Readonly-false input"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++++++TextView text:"Readonly-false input" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++EditText text:"Readonly-true input" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-readonly="true"}, {tabindex="0"}, {value="Readonly-true input"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++++++TextView text:"Readonly-true input" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"Readonly-false plain div" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Readonly-false plain div"}, {aria-readonly="false"}, {tabindex="0"}]
+++View text:"Readonly-true plain div" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Readonly-true plain div"}, {aria-readonly="true"}, {tabindex="0"}]
+++View text:"Readonly-false contenteditable div" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Readonly-false contenteditable div"}, {aria-readonly="false"}, {contenteditable=""}, {tabindex="0"}]
+++View text:"Readonly-true contenteditable div" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Readonly-true contenteditable div"}, {aria-readonly="true"}, {contenteditable=""}, {tabindex="0"}]
+++EditText text:"Readonly-false role unimplemented textbox" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Readonly-false role unimplemented textbox"}, {aria-readonly="false"}, {role="textbox"}, {tabindex="0"}]
+++EditText text:"Readonly-true role unimplemented textbox" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Readonly-true role unimplemented textbox"}, {aria-readonly="true"}, {role="textbox"}, {tabindex="0"}]
+++EditText text:"Readonly-false contenteditable textbox" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Readonly-false contenteditable textbox"}, {aria-readonly="false"}, {role="textbox"}, {tabindex="0"}]
+++EditText text:"Readonly-true contenteditable textbox" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Readonly-true contenteditable textbox"}, {aria-readonly="true"}, {role="textbox"}, {tabindex="0"}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}, {role="grid"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}, {role="row"}]
+++++++View text:"Readonly-false gridcell" textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {aria-label="Readonly-false gridcell"}, {aria-readonly="false"}, {role="gridcell"}, {tabindex="0"}]
+++++++View text:"Readonly-true gridcell" textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {aria-label="Readonly-true gridcell"}, {aria-readonly="true"}, {role="gridcell"}, {tabindex="0"}]
+++++++View text:"Readonly not specified gridcell" textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {aria-label="Readonly not specified gridcell"}, {role="gridcell"}, {tabindex="0"}]
+++CheckBox text:"Readonly checkbox" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Readonly checkbox"}, {aria-readonly="true"}, {role="checkbox"}]
+++EditText text:"Readonly combobox" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-label="Readonly combobox"}, {aria-readonly="true"}, {role="combobox"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++ListView text:"Readonly listbox" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Readonly listbox"}, {aria-readonly="true"}, {role="listbox"}]
+++RadioGroup text:"Readonly radiogroup" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Readonly radiogroup"}, {aria-readonly="true"}, {role="radiogroup"}]
+++SeekBar text:"Readonly slider" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Readonly slider"}, {aria-readonly="true"}, {role="slider"}]
+++EditText text:"Readonly spinbutton" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Readonly spinbutton"}, {aria-readonly="true"}, {role="spinbutton"}]
+++MenuItem text:"Readonly menuitemcheckbox" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Readonly menuitemcheckbox"}, {aria-readonly="true"}, {role="menuitemcheckbox"}]
+++MenuItem text:"Readonly menuitemradio" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Readonly menuitemradio"}, {aria-readonly="true"}, {role="menuitemradio"}]
+++EditText text:"Readonly searchbox" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Readonly searchbox"}, {aria-readonly="true"}, {role="searchbox"}]
+++ToggleButton text:"Readonly switch" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Readonly switch"}, {aria-readonly="true"}, {role="switch"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-region-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-region-expected-android-assist-data.txt
index 2d3e9f3..b981126 100644
--- a/content/test/data/accessibility/aria/aria-region-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-region-expected-android-assist-data.txt
@@ -1,14 +1,14 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="fieldset", role="region"]
-++++TextView text:"Unnamed ARIA region: must fall back to the native role." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="region"]
-++++TextView text:"Unnamed ARIA region on plain div uses generic container role." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"Named region" textSize:16.00 style:0 bundle:[aria-label="Named region", display="block", htmlTag="div", role="region"]
-++++TextView text:"Named ARIA region#1 gets the region role." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"Named ARIA region#2 gets the region role." textSize:16.00 style:0 bundle:[aria-labelledby="region-name", display="block", htmlTag="div", role="region"]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="region-name"]
-++++++TextView text:"Named ARIA region#2 gets the region role." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"Named region" textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="region", title="Named region"]
-++++TextView text:"Named ARIA region#3 gets the region role." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-roledescription="Regioneque region", display="block", htmlTag="div", role="region"]
-++++TextView text:"An aria-rolescription works on a nameless role=region." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="fieldset"}, {display="block"}, {role="region"}]
+++++TextView text:"Unnamed ARIA region: must fall back to the native role." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="region"}]
+++++TextView text:"Unnamed ARIA region on plain div uses generic container role." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"Named region" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Named region"}, {role="region"}]
+++++TextView text:"Named ARIA region#1 gets the region role." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"Named ARIA region#2 gets the region role." textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-labelledby="region-name"}, {role="region"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="region-name"}]
+++++++TextView text:"Named ARIA region#2 gets the region role." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"Named region" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="region"}, {title="Named region"}]
+++++TextView text:"Named ARIA region#3 gets the region role." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-roledescription="Regioneque region"}, {role="region"}]
+++++TextView text:"An aria-rolescription works on a nameless role=region." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-relevant-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-relevant-expected-android-assist-data.txt
index 1e3c819a..03fd7157 100644
--- a/content/test/data/accessibility/aria/aria-relevant-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-relevant-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[aria-relevant="additions", display="block", htmlTag="div", role="log", tabindex="0"]
-++View textSize:16.00 style:0 bundle:[aria-relevant="removals", display="block", htmlTag="div", role="log", tabindex="1"]
-++View textSize:16.00 style:0 bundle:[aria-relevant="text", display="block", htmlTag="div", role="log", tabindex="2"]
-++View textSize:16.00 style:0 bundle:[aria-relevant="all", display="block", htmlTag="div", role="log", tabindex="3"]
-++View textSize:16.00 style:0 bundle:[aria-relevant="additions text", display="block", htmlTag="div", role="log", tabindex="4"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-relevant="additions"}, {role="log"}, {tabindex="0"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-relevant="removals"}, {role="log"}, {tabindex="1"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-relevant="text"}, {role="log"}, {tabindex="2"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-relevant="all"}, {role="log"}, {tabindex="3"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-relevant="additions text"}, {role="log"}, {tabindex="4"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-required-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-required-expected-android-assist-data.txt
index 312f257e..d1d36e0 100644
--- a/content/test/data/accessibility/aria/aria-required-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-required-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++RadioGroup textSize:16.00 style:0 bundle:[aria-required="true", display="block", htmlTag="div", role="radiogroup"]
-++++RadioButton textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="radio"]
-++++RadioButton textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="radio"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++RadioGroup textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-required="true"}, {role="radiogroup"}]
+++++RadioButton textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="radio"}]
+++++RadioButton textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="radio"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-roledescription-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-roledescription-expected-android-assist-data.txt
index af7512f..00fbfd84 100644
--- a/content/test/data/accessibility/aria/aria-roledescription-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-roledescription-expected-android-assist-data.txt
@@ -1,15 +1,15 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="button"]
-++++TextView text:"Native button" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++Button textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="button"]
-++++TextView text:"ARIA button" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++Button textSize:16.00 style:0 bundle:[aria-roledescription="Clicky", display="block", htmlTag="div", role="button"]
-++++TextView text:"Clicky button" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-roledescription="Plain", display="block", htmlTag="div"]
-++++TextView text:"foo" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-roledescription="Focusable", display="block", htmlTag="div", tabindex="0"]
-++++TextView text:"bar" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-roledescription="Texty", display="block", htmlTag="p"]
-++++TextView text:"baz" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-roledescription="SuperContainer", display="block", htmlTag="div", role="group"]
-++++TextView text:"SuperContainer group" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}]
+++++TextView text:"Native button" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="button"}]
+++++TextView text:"ARIA button" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-roledescription="Clicky"}, {role="button"}]
+++++TextView text:"Clicky button" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-roledescription="Plain"}]
+++++TextView text:"foo" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-roledescription="Focusable"}, {tabindex="0"}]
+++++TextView text:"bar" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {aria-roledescription="Texty"}]
+++++TextView text:"baz" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-roledescription="SuperContainer"}, {role="group"}]
+++++TextView text:"SuperContainer group" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-row-attr-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-row-attr-expected-android-assist-data.txt
index 31e7b704..4b1676a 100644
--- a/content/test/data/accessibility/aria/aria-row-attr-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-row-attr-expected-android-assist-data.txt
@@ -1,14 +1,14 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++GridView textSize:16.00 style:0 bundle:[aria-rowcount="5", display="block", htmlTag="div", role="grid"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[aria-rowindex="3", display="inline", htmlTag="span", role="columnheader"]
-++++++++TextView text:"cell 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[aria-rowindex="3", display="inline", htmlTag="span", role="columnheader"]
-++++++++TextView text:"cell 3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[aria-rowindex="3", aria-rowspan="2", display="inline", htmlTag="span", role="columnheader"]
-++++++++TextView text:"cell 4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-rowindex="4", display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"cell 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"cell 3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-rowcount="5"}, {role="grid"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-rowindex="3"}, {role="columnheader"}]
+++++++++TextView text:"cell 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-rowindex="3"}, {role="columnheader"}]
+++++++++TextView text:"cell 3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-rowindex="3"}, {aria-rowspan="2"}, {role="columnheader"}]
+++++++++TextView text:"cell 4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-rowindex="4"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"cell 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"cell 3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-row-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-row-expected-android-assist-data.txt
index e19814b..0b1ed8b 100644
--- a/content/test/data/accessibility/aria/aria-row-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-row-expected-android-assist-data.txt
@@ -1,17 +1,17 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++GridView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="grid"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="columnheader"]
-++++++++TextView text:"Browser" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="columnheader"]
-++++++++TextView text:"Rendering Engine" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"Chrome" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"Blink" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"Safari" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"WebKit" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="grid"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="columnheader"}]
+++++++++TextView text:"Browser" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="columnheader"}]
+++++++++TextView text:"Rendering Engine" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"Chrome" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"Blink" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"Safari" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"WebKit" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-rowgroup-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-rowgroup-expected-android-assist-data.txt
index de0e630..21d4459a9 100644
--- a/content/test/data/accessibility/aria/aria-rowgroup-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-rowgroup-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++GridView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="grid"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="rowgroup"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="grid"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="rowgroup"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-rowheader-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-rowheader-expected-android-assist-data.txt
index 595e57f..8de17d7 100644
--- a/content/test/data/accessibility/aria/aria-rowheader-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-rowheader-expected-android-assist-data.txt
@@ -1,16 +1,16 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++GridView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="grid"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View text:"Browser" textSize:16.00 style:0 bundle:[aria-label="Browser", display="inline", htmlTag="span", role="rowheader"]
-++++++++TextView text:"Browser" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"Chrome" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"Safari" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View text:"Rendering Engine" textSize:16.00 style:0 bundle:[aria-label="Rendering Engine", display="inline", htmlTag="span", role="rowheader"]
-++++++++TextView text:"Rendering Engine" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"Blink" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"WebKit" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="grid"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View text:"Browser" textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-label="Browser"}, {role="rowheader"}]
+++++++++TextView text:"Browser" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"Chrome" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"Safari" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View text:"Rendering Engine" textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-label="Rendering Engine"}, {role="rowheader"}]
+++++++++TextView text:"Rendering Engine" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"Blink" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"WebKit" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-scrollbar-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-scrollbar-expected-android-assist-data.txt
index e0688b1..de65e06 100644
--- a/content/test/data/accessibility/aria/aria-scrollbar-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-scrollbar-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View text:"ScrollBar1" textSize:16.00 style:0 bundle:[aria-valuenow="55", display="block", htmlTag="div", role="scrollbar", tabindex="0"]
-++++TextView text:"ScrollBar1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"ScrollBar2" textSize:16.00 style:0 bundle:[aria-orientation="horizontal", aria-valuenow="55", class="test", display="block", htmlTag="div", role="scrollbar", tabindex="0"]
-++++TextView text:"ScrollBar2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View text:"ScrollBar1" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-valuenow="55"}, {role="scrollbar"}, {tabindex="0"}]
+++++TextView text:"ScrollBar1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"ScrollBar2" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-orientation="horizontal"}, {aria-valuenow="55"}, {role="scrollbar"}, {tabindex="0"}, {class="test"}]
+++++TextView text:"ScrollBar2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-search-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-search-expected-android-assist-data.txt
index 99daf75..d9002b4 100644
--- a/content/test/data/accessibility/aria/aria-search-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-search-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="search"]
-++++TextView text:"ARIA role search." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="search"}]
+++++TextView text:"ARIA role search." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-selected-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-selected-expected-android-assist-data.txt
index ddd9025..1ddea710 100644
--- a/content/test/data/accessibility/aria/aria-selected-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-selected-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", onclick="console.log('hi')", role="listbox"]
-++++View text:"1" textSize:16.00 style:0 bundle:[aria-label="1", aria-selected="true", display="block", htmlTag="div", role="option", tabindex="-1"]
-++++++TextView text:"Item 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View text:"2" textSize:16.00 style:0 bundle:[aria-label="2", aria-selected="false", display="block", htmlTag="div", role="option", tabindex="-1"]
-++++++TextView text:"Item 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {onclick="console.log('hi')"}, {role="listbox"}]
+++++View text:"1" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="1"}, {aria-selected="true"}, {role="option"}, {tabindex="-1"}]
+++++++TextView text:"Item 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View text:"2" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="2"}, {aria-selected="false"}, {role="option"}, {tabindex="-1"}]
+++++++TextView text:"Item 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-separator-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-separator-expected-android-assist-data.txt
index 65c1cacf..8b87a41 100644
--- a/content/test/data/accessibility/aria/aria-separator-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-separator-expected-android-assist-data.txt
@@ -1,7 +1,7 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++TextView text:"Before" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"ARIA separator. No value when unfocusable." textSize:16.00 style:0 bundle:[aria-valuemax="3", aria-valuemin="1", aria-valuenow="1", display="block", htmlTag="div", role="separator"]
-++++TextView text:"ARIA separator. No value when unfocusable." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"ARIA separator. Can have a value when focusable." textSize:16.00 style:0 bundle:[aria-valuemax="3", aria-valuemin="1", aria-valuenow="1", display="block", htmlTag="div", role="separator", tabindex="-1"]
-++++TextView text:"ARIA separator. Can have a value when focusable." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++TextView text:"After" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++TextView text:"Before" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"ARIA separator. No value when unfocusable." textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-valuemax="3"}, {aria-valuemin="1"}, {aria-valuenow="1"}, {role="separator"}]
+++++TextView text:"ARIA separator. No value when unfocusable." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"ARIA separator. Can have a value when focusable." textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-valuemax="3"}, {aria-valuemin="1"}, {aria-valuenow="1"}, {role="separator"}, {tabindex="-1"}]
+++++TextView text:"ARIA separator. Can have a value when focusable." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++TextView text:"After" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-setsize-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-setsize-expected-android-assist-data.txt
index 8fac38cf..79b3b22 100644
--- a/content/test/data/accessibility/aria/aria-setsize-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-setsize-expected-android-assist-data.txt
@@ -1,21 +1,21 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", onclick="console.log('hi')", role="listbox"]
-++++View textSize:16.00 style:0 bundle:[aria-posinset="1", aria-setsize="4", display="block", htmlTag="div", role="option", tabindex="0"]
-++++++TextView text:"Item 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-posinset="2", aria-setsize="4", display="block", htmlTag="div", role="option", tabindex="0"]
-++++++TextView text:"Item 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-posinset="3", aria-setsize="4", display="block", htmlTag="div", role="option", tabindex="0"]
-++++++TextView text:"Item 3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-posinset="4", aria-setsize="4", display="block", htmlTag="div", role="option", tabindex="0"]
-++++++TextView text:"Item 4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", onclick="console.log('hi')", role="listbox"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="option", tabindex="0"]
-++++++TextView text:"Item 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="option", tabindex="0"]
-++++++TextView text:"Item 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="option", tabindex="0"]
-++++++TextView text:"Item 3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="option", tabindex="0"]
-++++++TextView text:"Item 4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="option", tabindex="0"]
-++++++TextView text:"Item 5" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {onclick="console.log('hi')"}, {role="listbox"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-posinset="1"}, {aria-setsize="4"}, {role="option"}, {tabindex="0"}]
+++++++TextView text:"Item 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-posinset="2"}, {aria-setsize="4"}, {role="option"}, {tabindex="0"}]
+++++++TextView text:"Item 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-posinset="3"}, {aria-setsize="4"}, {role="option"}, {tabindex="0"}]
+++++++TextView text:"Item 3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-posinset="4"}, {aria-setsize="4"}, {role="option"}, {tabindex="0"}]
+++++++TextView text:"Item 4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {onclick="console.log('hi')"}, {role="listbox"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="option"}, {tabindex="0"}]
+++++++TextView text:"Item 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="option"}, {tabindex="0"}]
+++++++TextView text:"Item 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="option"}, {tabindex="0"}]
+++++++TextView text:"Item 3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="option"}, {tabindex="0"}]
+++++++TextView text:"Item 4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="option"}, {tabindex="0"}]
+++++++TextView text:"Item 5" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-slider-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-slider-expected-android-assist-data.txt
index ef21795..3905c9f 100644
--- a/content/test/data/accessibility/aria/aria-slider-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-slider-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++SeekBar text:"Slider" textSize:16.00 style:0 bundle:[aria-valuemax="10", aria-valuemin="1", aria-valuenow="5", display="block", htmlTag="div", role="slider"]
-++++TextView text:"Slider" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++SeekBar text:"Slider" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-valuemax="10"}, {aria-valuemin="1"}, {aria-valuenow="5"}, {role="slider"}]
+++++TextView text:"Slider" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-sort-aria-grid-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-sort-aria-grid-expected-android-assist-data.txt
index cb54a78..efe077899 100644
--- a/content/test/data/accessibility/aria/aria-sort-aria-grid-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-sort-aria-grid-expected-android-assist-data.txt
@@ -1,91 +1,91 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++GridView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="grid"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="columnheader"]
-++++++++TextView text:"Alphabet" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"B" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++GridView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="grid"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[aria-sort="none", display="inline", htmlTag="span", role="columnheader"]
-++++++++TextView text:"Alphabet" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"B" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++GridView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="grid"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[aria-sort="ascending", display="inline", htmlTag="span", role="columnheader"]
-++++++++TextView text:"Alphabet" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"B" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++GridView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="grid"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[aria-sort="descending", display="inline", htmlTag="span", role="columnheader"]
-++++++++TextView text:"Alphabet" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"B" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++GridView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="grid"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[aria-sort="other", display="inline", htmlTag="span", role="columnheader"]
-++++++++TextView text:"Alphabet" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++GridView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="grid"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="rowheader"]
-++++++++TextView text:"Alphabet" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"B" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++GridView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="grid"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[aria-sort="none", display="inline", htmlTag="span", role="rowheader"]
-++++++++TextView text:"Alphabet" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"B" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++GridView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="grid"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[aria-sort="ascending", display="inline", htmlTag="span", role="rowheader"]
-++++++++TextView text:"Alphabet" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"B" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++GridView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="grid"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[aria-sort="descending", display="inline", htmlTag="span", role="rowheader"]
-++++++++TextView text:"Alphabet" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"B" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++GridView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="grid"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[aria-sort="other", display="inline", htmlTag="span", role="rowheader"]
-++++++++TextView text:"Alphabet" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="gridcell"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="grid"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="columnheader"}]
+++++++++TextView text:"Alphabet" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"B" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="grid"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-sort="none"}, {role="columnheader"}]
+++++++++TextView text:"Alphabet" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"B" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="grid"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-sort="ascending"}, {role="columnheader"}]
+++++++++TextView text:"Alphabet" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"B" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="grid"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-sort="descending"}, {role="columnheader"}]
+++++++++TextView text:"Alphabet" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"B" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="grid"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-sort="other"}, {role="columnheader"}]
+++++++++TextView text:"Alphabet" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="grid"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="rowheader"}]
+++++++++TextView text:"Alphabet" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"B" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="grid"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-sort="none"}, {role="rowheader"}]
+++++++++TextView text:"Alphabet" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"B" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="grid"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-sort="ascending"}, {role="rowheader"}]
+++++++++TextView text:"Alphabet" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"B" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="grid"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-sort="descending"}, {role="rowheader"}]
+++++++++TextView text:"Alphabet" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"B" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="grid"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-sort="other"}, {role="rowheader"}]
+++++++++TextView text:"Alphabet" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="gridcell"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-sort-html-table-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-sort-html-table-expected-android-assist-data.txt
index 8678e2a..1e95195e 100644
--- a/content/test/data/accessibility/aria/aria-sort-html-table-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-sort-html-table-expected-android-assist-data.txt
@@ -1,103 +1,103 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++GridView text:"Data table" textSize:16.00 style:0 bundle:[display="table", htmlTag="table", summary="Data table"]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:1 bundle:[display="table-cell", htmlTag="th"]
-++++++++TextView text:"Alphabet" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"B" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++GridView text:"Data table" textSize:16.00 style:0 bundle:[display="table", htmlTag="table", summary="Data table"]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:1 bundle:[aria-sort="none", display="table-cell", htmlTag="th"]
-++++++++TextView text:"Alphabet" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"B" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++GridView text:"Data table" textSize:16.00 style:0 bundle:[display="table", htmlTag="table", summary="Data table"]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:1 bundle:[aria-sort="ascending", display="table-cell", htmlTag="th"]
-++++++++TextView text:"Alphabet" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"B" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++GridView text:"Data table" textSize:16.00 style:0 bundle:[display="table", htmlTag="table", summary="Data table"]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:1 bundle:[aria-sort="descending", display="table-cell", htmlTag="th"]
-++++++++TextView text:"Alphabet" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"B" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++GridView text:"Data table" textSize:16.00 style:0 bundle:[display="table", htmlTag="table", summary="Data table"]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:1 bundle:[aria-sort="other", display="table-cell", htmlTag="th"]
-++++++++TextView text:"Alphabet" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++GridView text:"Data table" textSize:16.00 style:0 bundle:[display="table", htmlTag="table", summary="Data table"]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:1 bundle:[display="table-cell", htmlTag="th"]
-++++++++TextView text:"Alphabet" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"B" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++GridView text:"Data table" textSize:16.00 style:0 bundle:[display="table", htmlTag="table", summary="Data table"]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:1 bundle:[aria-sort="none", display="table-cell", htmlTag="th"]
-++++++++TextView text:"Alphabet" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"B" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++GridView text:"Data table" textSize:16.00 style:0 bundle:[display="table", htmlTag="table", summary="Data table"]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:1 bundle:[aria-sort="ascending", display="table-cell", htmlTag="th"]
-++++++++TextView text:"Alphabet" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"B" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++GridView text:"Data table" textSize:16.00 style:0 bundle:[display="table", htmlTag="table", summary="Data table"]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:1 bundle:[aria-sort="descending", display="table-cell", htmlTag="th"]
-++++++++TextView text:"Alphabet" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"B" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++GridView text:"Data table" textSize:16.00 style:0 bundle:[display="table", htmlTag="table", summary="Data table"]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:1 bundle:[aria-sort="other", display="table-cell", htmlTag="th"]
-++++++++TextView text:"Alphabet" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++GridView text:"Data table" textSize:16.00 style:0 bundle:[display="table", htmlTag="table", summary="Data table"]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:1 bundle:[display="table-cell", htmlTag="th"]
-++++++++TextView text:"Alphabet" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[aria-sort="ascending", display="table-cell", htmlTag="td"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"B" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:1 bundle:[aria-sort="ascending", display="table-cell", htmlTag="th"]
-++++TextView text:"Alphabet" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++GridView text:"Data table" textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}, {summary="Data table"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}]
+++++++++TextView text:"Alphabet" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"B" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++GridView text:"Data table" textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}, {summary="Data table"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}, {aria-sort="none"}]
+++++++++TextView text:"Alphabet" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"B" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++GridView text:"Data table" textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}, {summary="Data table"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}, {aria-sort="ascending"}]
+++++++++TextView text:"Alphabet" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"B" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++GridView text:"Data table" textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}, {summary="Data table"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}, {aria-sort="descending"}]
+++++++++TextView text:"Alphabet" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"B" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++GridView text:"Data table" textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}, {summary="Data table"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}, {aria-sort="other"}]
+++++++++TextView text:"Alphabet" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++GridView text:"Data table" textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}, {summary="Data table"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}]
+++++++++TextView text:"Alphabet" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"B" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++GridView text:"Data table" textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}, {summary="Data table"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}, {aria-sort="none"}]
+++++++++TextView text:"Alphabet" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"B" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++GridView text:"Data table" textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}, {summary="Data table"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}, {aria-sort="ascending"}]
+++++++++TextView text:"Alphabet" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"B" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++GridView text:"Data table" textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}, {summary="Data table"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}, {aria-sort="descending"}]
+++++++++TextView text:"Alphabet" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"B" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++GridView text:"Data table" textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}, {summary="Data table"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}, {aria-sort="other"}]
+++++++++TextView text:"Alphabet" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++GridView text:"Data table" textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}, {summary="Data table"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}]
+++++++++TextView text:"Alphabet" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {aria-sort="ascending"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"B" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}, {aria-sort="ascending"}]
+++++TextView text:"Alphabet" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-status-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-status-expected-android-assist-data.txt
index 8416d62..483153db 100644
--- a/content/test/data/accessibility/aria/aria-status-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-status-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="status"]
-++View textSize:16.00 style:0 bundle:[aria-atomic="false", display="block", htmlTag="div", role="status"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="status"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-atomic="false"}, {role="status"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-strong-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-strong-expected-android-assist-data.txt
index 8dfbbd1..594b7db 100644
--- a/content/test/data/accessibility/aria/aria-strong-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-strong-expected-android-assist-data.txt
@@ -1,7 +1,7 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="strong"]
-++++TextView text:"role" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++TextView text:"element (no name)" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"include me" textSize:16.00 style:1 bundle:[aria-label="include me", display="inline", htmlTag="strong"]
-++++TextView text:"element (with name)" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="strong"}]
+++++TextView text:"role" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++TextView text:"element (no name)" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"include me" textSize:16.0 style:1 htmlInfo:[{htmlTag="strong"}, {display="inline"}, {aria-label="include me"}]
+++++TextView text:"element (with name)" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-subscript-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-subscript-expected-android-assist-data.txt
index 86413c6..7af9b8e 100644
--- a/content/test/data/accessibility/aria/aria-subscript-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-subscript-expected-android-assist-data.txt
@@ -1,21 +1,21 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"This text contains " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="subscript"]
-++++++TextView text:"subscript" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" text." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"H" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="subscript"]
-++++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:8 bundle:[display="inline", htmlTag="del"]
-++++++++View textSize:16.00 style:8 bundle:[display="inline", htmlTag="span", tabindex="0"]
-++++++++++View text:"oops" textSize:16.00 style:8 bundle:[display="inline", htmlTag="span", title="oops"]
-++++++++++++TextView text:"3" textSize:16.00 style:8 bundle:[display="", htmlTag=""]
-++++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:4 bundle:[display="inline", htmlTag="ins"]
-++++++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#", htmlTag="a"]
-++++++++++View text:"better" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", htmlTag="span", title="better"]
-++++++++++++TextView text:"2" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"O" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"This text contains " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="subscript"}]
+++++++TextView text:"subscript" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" text." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"H" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="subscript"}]
+++++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:8 htmlInfo:[{htmlTag="del"}, {display="inline"}]
+++++++++View textSize:16.0 style:8 htmlInfo:[{htmlTag="span"}, {display="inline"}, {tabindex="0"}]
+++++++++++View text:"oops" textSize:16.0 style:8 htmlInfo:[{htmlTag="span"}, {display="inline"}, {title="oops"}]
+++++++++++++TextView text:"3" textSize:16.0 style:8 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:4 htmlInfo:[{htmlTag="ins"}, {display="inline"}]
+++++++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#"}]
+++++++++++View text:"better" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="span"}, {display="inline"}, {title="better"}]
+++++++++++++TextView text:"2" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"O" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-superscript-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-superscript-expected-android-assist-data.txt
index a780687a..9413c6d 100644
--- a/content/test/data/accessibility/aria/aria-superscript-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-superscript-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"This text contains " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="superscript"]
-++++++TextView text:"superscript" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" text." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"This text contains " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="superscript"}]
+++++++TextView text:"superscript" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" text." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-switch-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-switch-expected-android-assist-data.txt
index 8651bf83..3cc0b95 100644
--- a/content/test/data/accessibility/aria/aria-switch-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-switch-expected-android-assist-data.txt
@@ -1,9 +1,9 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ToggleButton textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="switch"]
-++++TextView text:"Switch1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ToggleButton textSize:16.00 style:0 bundle:[aria-checked="false", display="block", htmlTag="div", role="switch"]
-++++TextView text:"Switch2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ToggleButton textSize:16.00 style:0 bundle:[aria-checked="true", display="block", htmlTag="div", role="switch"]
-++++TextView text:"Switch3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ToggleButton textSize:16.00 style:0 bundle:[aria-checked="mixed", display="block", htmlTag="div", role="switch"]
-++++TextView text:"Switch4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ToggleButton textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="switch"}]
+++++TextView text:"Switch1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ToggleButton textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-checked="false"}, {role="switch"}]
+++++TextView text:"Switch2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ToggleButton textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-checked="true"}, {role="switch"}]
+++++TextView text:"Switch3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ToggleButton textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-checked="mixed"}, {role="switch"}]
+++++TextView text:"Switch4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-tab-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-tab-expected-android-assist-data.txt
index c917a4c0..387d863 100644
--- a/content/test/data/accessibility/aria/aria-tab-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-tab-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++TabWidget textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="tablist"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="tab1", role="tab"]
-++++++TextView text:"Tab 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="tab2", role="tab"]
-++++++TextView text:"Tab 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++TabWidget textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="tablist"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="tab1"}, {role="tab"}]
+++++++TextView text:"Tab 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="tab2"}, {role="tab"}]
+++++++TextView text:"Tab 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-tab-nested-in-lists-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-tab-nested-in-lists-expected-android-assist-data.txt
index a37adb59..4277b82 100644
--- a/content/test/data/accessibility/aria/aria-tab-nested-in-lists-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-tab-nested-in-lists-expected-android-assist-data.txt
@@ -1,10 +1,10 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++TabWidget textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", role="tablist"]
-++++View textSize:16.00 style:0 bundle:[aria-posinset="2", aria-setsize="5", display="block", htmlTag="div", role="tab"]
-++++++TextView text:"tab1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-posinset="3", aria-setsize="5", display="block", htmlTag="div", role="tab"]
-++++++TextView text:"tab2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-posinset="4", aria-setsize="5", display="block", htmlTag="div", role="tab"]
-++++++TextView text:"tab3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-posinset="5", aria-setsize="5", display="block", htmlTag="div", role="tab"]
-++++++TextView text:"tab4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++TabWidget textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {role="tablist"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-posinset="2"}, {aria-setsize="5"}, {role="tab"}]
+++++++TextView text:"tab1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-posinset="3"}, {aria-setsize="5"}, {role="tab"}]
+++++++TextView text:"tab2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-posinset="4"}, {aria-setsize="5"}, {role="tab"}]
+++++++TextView text:"tab3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-posinset="5"}, {aria-setsize="5"}, {role="tab"}]
+++++++TextView text:"tab4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-table-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-table-expected-android-assist-data.txt
index 6292ee03..898d563 100644
--- a/content/test/data/accessibility/aria/aria-table-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-table-expected-android-assist-data.txt
@@ -1,12 +1,12 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++GridView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="table"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="columnheader"]
-++++++++TextView text:"Browser" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="columnheader"]
-++++++++TextView text:"Rendering Engine" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="row"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="cell"]
-++++++++TextView text:"Chrome" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", role="cell"]
-++++++++TextView text:"Blink" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="table"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="columnheader"}]
+++++++++TextView text:"Browser" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="columnheader"}]
+++++++++TextView text:"Rendering Engine" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="cell"}]
+++++++++TextView text:"Chrome" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {role="cell"}]
+++++++++TextView text:"Blink" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-tablist-aria-level-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-tablist-aria-level-expected-android-assist-data.txt
index de54a2c..45e6af5 100644
--- a/content/test/data/accessibility/aria/aria-tablist-aria-level-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-tablist-aria-level-expected-android-assist-data.txt
@@ -1,22 +1,22 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++TabWidget textSize:16.00 style:0 bundle:[aria-level="1", display="block", htmlTag="div", role="tablist"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="tab"]
-++++++TextView text:"Tab 1 of 2, level 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="tab"]
-++++++TextView text:"Tab 2 of 2, level 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++TabWidget textSize:16.00 style:0 bundle:[aria-level="2", display="block", htmlTag="div", role="tablist"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="tab"]
-++++++TextView text:"Tab 1 of 3, level 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="tab"]
-++++++TextView text:"Tab 2 of 3, level 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TabWidget textSize:16.00 style:0 bundle:[aria-level="3", display="block", htmlTag="div", role="tablist"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="tab"]
-++++++++TextView text:"Tab 1 of 1, level 3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="tab"]
-++++++TextView text:"Tab 3 of 3, level 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++TabWidget textSize:16.00 style:0 bundle:[aria-level="2", display="block", htmlTag="div", role="tablist"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="tab"]
-++++++TextView text:"Tab 1 of 1, level 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++TabWidget textSize:16.00 style:0 bundle:[aria-level="1", display="block", htmlTag="div", role="tablist"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="tab"]
-++++++TextView text:"Tab 1 of 1, level 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++TabWidget textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-level="1"}, {role="tablist"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="tab"}]
+++++++TextView text:"Tab 1 of 2, level 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="tab"}]
+++++++TextView text:"Tab 2 of 2, level 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++TabWidget textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-level="2"}, {role="tablist"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="tab"}]
+++++++TextView text:"Tab 1 of 3, level 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="tab"}]
+++++++TextView text:"Tab 2 of 3, level 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TabWidget textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-level="3"}, {role="tablist"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="tab"}]
+++++++++TextView text:"Tab 1 of 1, level 3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="tab"}]
+++++++TextView text:"Tab 3 of 3, level 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++TabWidget textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-level="2"}, {role="tablist"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="tab"}]
+++++++TextView text:"Tab 1 of 1, level 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++TabWidget textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-level="1"}, {role="tablist"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="tab"}]
+++++++TextView text:"Tab 1 of 1, level 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-tablist-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-tablist-expected-android-assist-data.txt
index 5af138c..53e1dcc 100644
--- a/content/test/data/accessibility/aria/aria-tablist-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-tablist-expected-android-assist-data.txt
@@ -1,16 +1,16 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++TabWidget textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="tablist"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="tab"]
-++++++TextView text:"Tab 1, level 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="tab"]
-++++++TextView text:"Tab 2, level 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TabWidget textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", role="tablist"]
-++++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", role="tab"]
-++++++++TextView text:"Tab 1, level 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", role="tab"]
-++++++++TextView text:"Tab 2, level 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++TabWidget textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", role="tablist"]
-++++++++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", role="tab"]
-++++++++++++TextView text:"Tab 1, level 3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="tab"]
-++++++TextView text:"Tab 3, level 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++TabWidget textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="tablist"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="tab"}]
+++++++TextView text:"Tab 1, level 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="tab"}]
+++++++TextView text:"Tab 2, level 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TabWidget textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {role="tablist"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {role="tab"}]
+++++++++TextView text:"Tab 1, level 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {role="tab"}]
+++++++++TextView text:"Tab 2, level 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++TabWidget textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {role="tablist"}]
+++++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {role="tab"}]
+++++++++++++TextView text:"Tab 1, level 3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="tab"}]
+++++++TextView text:"Tab 3, level 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-tabpanel-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-tabpanel-expected-android-assist-data.txt
index 3f8071d..6bd4132 100644
--- a/content/test/data/accessibility/aria/aria-tabpanel-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-tabpanel-expected-android-assist-data.txt
@@ -1,10 +1,10 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++TabWidget textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="tablist"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="item", role="tab"]
-++++++View textSize:18.72 style:1 bundle:[display="block", htmlTag="h3"]
-++++++++TextView text:"Item" textSize:18.72 style:1 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="prices", role="tab"]
-++++++View textSize:18.72 style:1 bundle:[display="block", htmlTag="h3"]
-++++++++TextView text:"Prices" textSize:18.72 style:1 bundle:[display="", htmlTag=""]
-++View text:"Item" textSize:16.00 style:0 bundle:[aria-labelledby="item", display="block", htmlTag="div", role="tabpanel"]
-++++TextView text:"Item tab content" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++TabWidget textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="tablist"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="item"}, {role="tab"}]
+++++++View textSize:18.7 style:1 htmlInfo:[{htmlTag="h3"}, {display="block"}]
+++++++++TextView text:"Item" textSize:18.7 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="prices"}, {role="tab"}]
+++++++View textSize:18.7 style:1 htmlInfo:[{htmlTag="h3"}, {display="block"}]
+++++++++TextView text:"Prices" textSize:18.7 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"Item" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-labelledby="item"}, {role="tabpanel"}]
+++++TextView text:"Item tab content" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-term-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-term-expected-android-assist-data.txt
index 7d62b60..00ceb87 100644
--- a/content/test/data/accessibility/aria/aria-term-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-term-expected-android-assist-data.txt
@@ -1,10 +1,10 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="list"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="term"]
-++++++TextView text:"Term1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="definition"]
-++++++TextView text:"Definition1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="term"]
-++++++TextView text:"Term2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="definition"]
-++++++TextView text:"Definition2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="list"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="term"}]
+++++++TextView text:"Term1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="definition"}]
+++++++TextView text:"Definition1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="term"}]
+++++++TextView text:"Term2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="definition"}]
+++++++TextView text:"Definition2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-textbox-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-textbox-expected-android-assist-data.txt
index 3f57fba..0be3227 100644
--- a/content/test/data/accessibility/aria/aria-textbox-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-textbox-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++EditText text:"\n    TextBox1\n  " textSize:16.00 style:0 bundle:[contenteditable="plaintext-only", display="block", htmlTag="div", role="textbox"]
-++++TextView text:"\n    TextBox1\n  " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++EditText text:"\n    TextBox2\n  " textSize:16.00 style:0 bundle:[aria-multiline="true", contenteditable="plaintext-only", display="block", htmlTag="div", role="textbox"]
-++++TextView text:"\n    TextBox2\n  " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++EditText text:"\n    TextBox1\n  " textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {contenteditable="plaintext-only"}, {role="textbox"}]
+++++TextView text:"\n    TextBox1\n  " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++EditText text:"\n    TextBox2\n  " textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-multiline="true"}, {contenteditable="plaintext-only"}, {role="textbox"}]
+++++TextView text:"\n    TextBox2\n  " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-textbox-with-aria-textbox-child-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-textbox-with-aria-textbox-child-expected-android-assist-data.txt
index 935450aa..884c2e3 100644
--- a/content/test/data/accessibility/aria/aria-textbox-with-aria-textbox-child-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-textbox-with-aria-textbox-child-expected-android-assist-data.txt
@@ -1,27 +1,27 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++EditText text:"Foo\nBar\nBar\nBaz\nBaz" textSize:16.00 style:0 bundle:[aria-label="not editable", display="block", htmlTag="div", role="textbox"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++TextView text:"Foo" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++EditText text:"Bar" textSize:16.00 style:0 bundle:[aria-label="nested, not editable, rich", display="block", htmlTag="div", role="textbox"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"Bar" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++EditText text:"Bar" textSize:16.00 style:0 bundle:[aria-label="nested, not editable, plain", display="block", htmlTag="div", role="textbox"]
-++++++TextView text:"Bar" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++EditText text:"Baz" textSize:16.00 style:0 bundle:[aria-label="nested, editable, rich", contenteditable="", display="block", htmlTag="div", role="textbox"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"Baz" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++EditText text:"Baz" textSize:16.00 style:0 bundle:[aria-label="nested, editable, plain", contenteditable="", display="block", htmlTag="div", role="textbox"]
-++++++TextView text:"Baz" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++EditText text:"Foo\nBar\nBar\nBaz\nBaz" textSize:16.00 style:0 bundle:[aria-label="editable", contenteditable="", display="block", htmlTag="div", role="textbox"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++TextView text:"Foo" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++EditText text:"Baz" textSize:16.00 style:0 bundle:[aria-label="nested, not editable, rich", display="block", htmlTag="div", role="textbox"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"Bar" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++EditText text:"Bar" textSize:16.00 style:0 bundle:[aria-label="nested, not editable, plain", display="block", htmlTag="div", role="textbox"]
-++++++TextView text:"Bar" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++EditText text:"Baz" textSize:16.00 style:0 bundle:[aria-label="nested, editable, rich", contenteditable="", display="block", htmlTag="div", role="textbox"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"Baz" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++EditText text:"Bar" textSize:16.00 style:0 bundle:[aria-label="nested, editable, plain", contenteditable="", display="block", htmlTag="div", role="textbox"]
-++++++TextView text:"Baz" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++EditText text:"Foo\nBar\nBar\nBaz\nBaz" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="not editable"}, {role="textbox"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++TextView text:"Foo" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++EditText text:"Bar" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="nested, not editable, rich"}, {role="textbox"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"Bar" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++EditText text:"Bar" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="nested, not editable, plain"}, {role="textbox"}]
+++++++TextView text:"Bar" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++EditText text:"Baz" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="nested, editable, rich"}, {contenteditable=""}, {role="textbox"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"Baz" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++EditText text:"Baz" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="nested, editable, plain"}, {contenteditable=""}, {role="textbox"}]
+++++++TextView text:"Baz" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++EditText text:"Foo\nBar\nBar\nBaz\nBaz" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="editable"}, {contenteditable=""}, {role="textbox"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++TextView text:"Foo" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++EditText text:"Baz" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="nested, not editable, rich"}, {role="textbox"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"Bar" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++EditText text:"Bar" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="nested, not editable, plain"}, {role="textbox"}]
+++++++TextView text:"Bar" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++EditText text:"Baz" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="nested, editable, rich"}, {contenteditable=""}, {role="textbox"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"Baz" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++EditText text:"Bar" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="nested, editable, plain"}, {contenteditable=""}, {role="textbox"}]
+++++++TextView text:"Baz" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-textbox-with-non-text-children-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-textbox-with-non-text-children-expected-android-assist-data.txt
index 9cee91a..608a50f 100644
--- a/content/test/data/accessibility/aria/aria-textbox-with-non-text-children-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-textbox-with-non-text-children-expected-android-assist-data.txt
@@ -1,36 +1,36 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++EditText text:"focusable: oklink name: \n" textSize:16.00 style:0 bundle:[aria-label="not editable", display="block", htmlTag="div", role="textbox", tabindex="0"]
-++++TextView text:"focusable: " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="button"]
-++++++TextView text:"ok" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#", htmlTag="a"]
-++++++TextView text:"link" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="label"]
-++++++TextView text:"name: " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++EditText text:"name:" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input"]
-++++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++EditText text:"focusable: oklink name: \n" textSize:16.00 style:0 bundle:[aria-label="editable", contenteditable="", display="block", htmlTag="div", role="textbox"]
-++++TextView text:"focusable: " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="button"]
-++++++TextView text:"ok" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#", htmlTag="a"]
-++++++TextView text:"link" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="label"]
-++++++TextView text:"name: " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++EditText text:"name:" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input"]
-++++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++EditText text:"focusable: oklink name: \n" textSize:16.00 style:0 bundle:[aria-label="not editable or focusable", display="block", htmlTag="div", role="textbox"]
-++++TextView text:"focusable: " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="button"]
-++++++TextView text:"ok" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#", htmlTag="a"]
-++++++TextView text:"link" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="label"]
-++++++TextView text:"name: " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++EditText text:"name:" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input"]
-++++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++EditText text:"not editable, img child" textSize:16.00 style:0 bundle:[aria-label="not editable, img child", display="block", htmlTag="div", role="textbox"]
-++++Image textSize:16.00 style:0 bundle:[display="inline", htmlTag="img"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++EditText text:"focusable: oklink name: \n" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="not editable"}, {role="textbox"}, {tabindex="0"}]
+++++TextView text:"focusable: " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}]
+++++++TextView text:"ok" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#"}]
+++++++TextView text:"link" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="label"}, {display="inline"}]
+++++++TextView text:"name: " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++EditText text:"name:" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}]
+++++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++EditText text:"focusable: oklink name: \n" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="editable"}, {contenteditable=""}, {role="textbox"}]
+++++TextView text:"focusable: " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}]
+++++++TextView text:"ok" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#"}]
+++++++TextView text:"link" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="label"}, {display="inline"}]
+++++++TextView text:"name: " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++EditText text:"name:" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}]
+++++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++EditText text:"focusable: oklink name: \n" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="not editable or focusable"}, {role="textbox"}]
+++++TextView text:"focusable: " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}]
+++++++TextView text:"ok" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#"}]
+++++++TextView text:"link" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="label"}, {display="inline"}]
+++++++TextView text:"name: " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++EditText text:"name:" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}]
+++++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++EditText text:"not editable, img child" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="not editable, img child"}, {role="textbox"}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="img"}, {display="inline"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-time-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-time-expected-android-assist-data.txt
index 94d69ba..9867998 100644
--- a/content/test/data/accessibility/aria/aria-time-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-time-expected-android-assist-data.txt
@@ -1,8 +1,8 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="time"]
-++++TextView text:"role" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="time"]
-++++TextView text:"element (no name)" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"include me" textSize:16.00 style:0 bundle:[aria-label="include me", display="inline", htmlTag="time"]
-++++TextView text:"element (with name)" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="time"}]
+++++TextView text:"role" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="time"}, {display="inline"}]
+++++TextView text:"element (no name)" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"include me" textSize:16.0 style:0 htmlInfo:[{htmlTag="time"}, {display="inline"}, {aria-label="include me"}]
+++++TextView text:"element (with name)" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-timer-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-timer-expected-android-assist-data.txt
index aab6cef..be8a84e 100644
--- a/content/test/data/accessibility/aria/aria-timer-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-timer-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[aria-live="polite", display="block", htmlTag="div", role="timer"]
-++++TextView text:"This test is for aria-role = timer" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-live="polite"}, {role="timer"}]
+++++TextView text:"This test is for aria-role = timer" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-togglebutton-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-togglebutton-expected-android-assist-data.txt
index 724011c..8b24e03 100644
--- a/content/test/data/accessibility/aria/aria-togglebutton-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-togglebutton-expected-android-assist-data.txt
@@ -1,9 +1,9 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++Button textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="button", tabindex="0"]
-++++TextView text:"Regular button" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ToggleButton textSize:16.00 style:0 bundle:[aria-pressed="false", display="block", htmlTag="div", role="button", tabindex="0"]
-++++TextView text:"Toggle button" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ToggleButton textSize:16.00 style:0 bundle:[aria-pressed="true", display="block", htmlTag="div", role="button", tabindex="0"]
-++++TextView text:"Toggle button" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ToggleButton textSize:16.00 style:0 bundle:[aria-pressed="mixed", display="block", htmlTag="div", role="button", tabindex="0"]
-++++TextView text:"Toggle button" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++Button textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="button"}, {tabindex="0"}]
+++++TextView text:"Regular button" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ToggleButton textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-pressed="false"}, {role="button"}, {tabindex="0"}]
+++++TextView text:"Toggle button" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ToggleButton textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-pressed="true"}, {role="button"}, {tabindex="0"}]
+++++TextView text:"Toggle button" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ToggleButton textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-pressed="mixed"}, {role="button"}, {tabindex="0"}]
+++++TextView text:"Toggle button" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-toolbar-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-toolbar-expected-android-assist-data.txt
index eaf99dd8..6a05553 100644
--- a/content/test/data/accessibility/aria/aria-toolbar-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-toolbar-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="toolbar"]
-++++TextView text:"A toolbar" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="toolbar"}]
+++++TextView text:"A toolbar" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-tooltip-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-tooltip-expected-android-assist-data.txt
index 400c8a7..e6d0a8e 100644
--- a/content/test/data/accessibility/aria/aria-tooltip-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-tooltip-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++EditText text:"Your username should be your email id" textSize:13.33 style:0 bundle:[aria-describedby="username-tip", display="inline-block", htmlTag="input", id="username", type="text"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="username-tip", role="tooltip"]
-++++TextView text:"Your username should be your email id" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++EditText text:"Your username should be your email id" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-describedby="username-tip"}, {id="username"}, {type="text"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="username-tip"}, {role="tooltip"}]
+++++TextView text:"Your username should be your email id" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-tree-discontinuous-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-tree-discontinuous-expected-android-assist-data.txt
index 17472e0..01c934bb 100644
--- a/content/test/data/accessibility/aria/aria-tree-discontinuous-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-tree-discontinuous-expected-android-assist-data.txt
@@ -1,7 +1,7 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="tree"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="treeitem", tabindex="0"]
-++++++TextView text:"card content" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-hidden="false", display="block", htmlTag="div"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="treeitem", tabindex="0"]
-++++++TextView text:"card content" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="tree"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="treeitem"}, {tabindex="0"}]
+++++++TextView text:"card content" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-hidden="false"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="treeitem"}, {tabindex="0"}]
+++++++TextView text:"card content" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-tree-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-tree-expected-android-assist-data.txt
index dd44cac..3e903eb1 100644
--- a/content/test/data/accessibility/aria/aria-tree-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-tree-expected-android-assist-data.txt
@@ -1,22 +1,22 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", role="tree"]
-++++View textSize:16.00 style:0 bundle:[aria-checked="mixed", display="list-item", htmlTag="li", role="treeitem"]
-++++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#animals", htmlTag="a"]
-++++++++TextView text:"Animals" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", role="group"]
-++++++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", role="treeitem"]
-++++++++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#domesticated", htmlTag="a"]
-++++++++++++TextView text:"Domesticated" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", role="group"]
-++++++++++++View textSize:16.00 style:0 bundle:[aria-checked="true", display="list-item", htmlTag="li", role="treeitem"]
-++++++++++++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#dog", htmlTag="a"]
-++++++++++++++++TextView text:"Dog" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++++++++++View textSize:16.00 style:0 bundle:[aria-checked="false", display="list-item", htmlTag="li", role="treeitem"]
-++++++++++++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#cat", htmlTag="a"]
-++++++++++++++++TextView text:"Cat" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", role="treeitem"]
-++++++++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#wild", htmlTag="a"]
-++++++++++++TextView text:"Wild" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", role="treeitem"]
-++++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#plants", htmlTag="a"]
-++++++++TextView text:"Plants" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {role="tree"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-checked="mixed"}, {role="treeitem"}]
+++++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#animals"}]
+++++++++TextView text:"Animals" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {role="group"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {role="treeitem"}]
+++++++++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#domesticated"}]
+++++++++++++TextView text:"Domesticated" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {role="group"}]
+++++++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-checked="true"}, {role="treeitem"}]
+++++++++++++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#dog"}]
+++++++++++++++++TextView text:"Dog" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-checked="false"}, {role="treeitem"}]
+++++++++++++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#cat"}]
+++++++++++++++++TextView text:"Cat" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {role="treeitem"}]
+++++++++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#wild"}]
+++++++++++++TextView text:"Wild" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {role="treeitem"}]
+++++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#plants"}]
+++++++++TextView text:"Plants" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-treegrid-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-treegrid-expected-android-assist-data.txt
index 692f984..ce85bc97 100644
--- a/content/test/data/accessibility/aria/aria-treegrid-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-treegrid-expected-android-assist-data.txt
@@ -1,79 +1,79 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++GridView textSize:16.00 style:0 bundle:[display="table", htmlTag="table", role="treegrid"]
-++++View textSize:16.00 style:0 bundle:[aria-level="1", display="table-row", htmlTag="tr", role="row", tabindex="-1"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td", role="gridcell"]
-++++++++TextView text:"Cell 1, row 1, level 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td", role="gridcell"]
-++++++++TextView text:"Cell 2, row 1, level 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-level="1", display="table-row", htmlTag="tr", role="row", tabindex="-1"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td", role="gridcell"]
-++++++++TextView text:"Cell 1, row 2, level 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td", role="gridcell"]
-++++++++TextView text:"Cell 2, row 2, level 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-level="1", display="table-row", htmlTag="tr", role="row", tabindex="-1"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td", role="gridcell"]
-++++++++TextView text:"Cell 1, row 3, level 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td", role="gridcell"]
-++++++++TextView text:"Cell 2, row 3, level 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-level="2", display="table-row", htmlTag="tr", role="row", tabindex="-1"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td", role="gridcell"]
-++++++++TextView text:"Cell 1, row 1, level 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-level="2", display="table-row", htmlTag="tr", role="row", tabindex="-1"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td", role="gridcell"]
-++++++++TextView text:"Cell 1, row 2, level 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-level="2", display="table-row", htmlTag="tr", role="row", tabindex="-1"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td", role="gridcell"]
-++++++++TextView text:"Cell 1, row 3, level 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-level="2", display="table-row", htmlTag="tr", role="row", tabindex="-1"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td", role="gridcell"]
-++++++++TextView text:"Cell 1, row 4, level 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-level="3", display="table-row", htmlTag="tr", role="row", tabindex="-1"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td", role="gridcell"]
-++++++++TextView text:"Cell 1, row 2, level 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++GridView textSize:16.00 style:0 bundle:[display="table", htmlTag="table", role="treegrid"]
-++++View textSize:16.00 style:0 bundle:[display="table-row-group", htmlTag="tbody", role="rowgroup"]
-++++++View textSize:16.00 style:0 bundle:[aria-level="1", display="table-row", htmlTag="tr", role="row", tabindex="-1"]
-++++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td", role="gridcell"]
-++++++++++TextView text:"Cell 1, row 1, rowgroup 1, level 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[aria-level="1", display="table-row", htmlTag="tr", role="row", tabindex="-1"]
-++++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td", role="gridcell"]
-++++++++++TextView text:"Cell 1, row 2, rowgroup 1, level 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[aria-level="1", display="table-row", htmlTag="tr", role="row", tabindex="-1"]
-++++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td", role="gridcell"]
-++++++++++TextView text:"Cell 1, row 3, rowgroup 1, level 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[aria-level="2", display="table-row", htmlTag="tr", role="row", tabindex="-1"]
-++++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td", role="gridcell"]
-++++++++++TextView text:"Cell 1, row 1, rowgroup 1, level 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[aria-level="1", display="table-row", htmlTag="tr", role="row", tabindex="-1"]
-++++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td", role="gridcell"]
-++++++++++TextView text:"Cell 1, row 1, rowgroup 1, level 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row-group", htmlTag="tbody", role="rowgroup"]
-++++++View textSize:16.00 style:0 bundle:[aria-level="1", display="table-row", htmlTag="tr", role="row", tabindex="-1"]
-++++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td", role="gridcell"]
-++++++++++TextView text:"Cell 1, row 1, rowgroup 2, level 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td", role="gridcell"]
-++++++++++TextView text:"Cell 2, row 1, rowgroup 2, level 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[aria-level="2", display="table-row", htmlTag="tr", role="row", tabindex="-1"]
-++++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td", role="gridcell"]
-++++++++++TextView text:"Cell 1, row 1, rowgroup 2, level 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td", role="gridcell"]
-++++++++++TextView text:"Cell 2, row 1, rowgroup 2, level 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td", role="gridcell"]
-++++++++++TextView text:"Cell 3, row 1, rowgroup 2, level 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++GridView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="treegrid"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="rowgroup"]
-++++++View textSize:16.00 style:0 bundle:[aria-level="1", display="block", htmlTag="div", role="row", tabindex="-1"]
-++++++++TextView text:"Cell 1, row 1, rowgroup 1, level 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[aria-level="1", display="block", htmlTag="div", role="row", tabindex="-1"]
-++++++++TextView text:"Cell 1, row 2, rowgroup 1, level 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[aria-level="1", display="block", htmlTag="div", role="row", tabindex="-1"]
-++++++++TextView text:"Cell 1, row 3, rowgroup 1, level 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[aria-level="2", display="block", htmlTag="div", role="row", tabindex="-1"]
-++++++++TextView text:"Cell 1, row 1, rowgroup 1, level 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[aria-level="1", display="block", htmlTag="div", role="row", tabindex="-1"]
-++++++++TextView text:"Cell 1, row 1, rowgroup 1, level 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="rowgroup"]
-++++++View textSize:16.00 style:0 bundle:[aria-level="1", display="block", htmlTag="div", role="row", tabindex="-1"]
-++++++++TextView text:"Cell 1, row 1, rowgroup 2, level 1 Cell 2, row 1, rowgroup 2, level 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[aria-level="2", display="block", htmlTag="div", role="row", tabindex="-1"]
-++++++++TextView text:"Cell 1, row 1, rowgroup 2, level 2 Cell 2, row 1, rowgroup 2, level 2 Cell 3, row 1, rowgroup 2, level 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}, {role="treegrid"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}, {aria-level="1"}, {role="row"}, {tabindex="-1"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {role="gridcell"}]
+++++++++TextView text:"Cell 1, row 1, level 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {role="gridcell"}]
+++++++++TextView text:"Cell 2, row 1, level 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}, {aria-level="1"}, {role="row"}, {tabindex="-1"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {role="gridcell"}]
+++++++++TextView text:"Cell 1, row 2, level 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {role="gridcell"}]
+++++++++TextView text:"Cell 2, row 2, level 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}, {aria-level="1"}, {role="row"}, {tabindex="-1"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {role="gridcell"}]
+++++++++TextView text:"Cell 1, row 3, level 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {role="gridcell"}]
+++++++++TextView text:"Cell 2, row 3, level 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}, {aria-level="2"}, {role="row"}, {tabindex="-1"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {role="gridcell"}]
+++++++++TextView text:"Cell 1, row 1, level 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}, {aria-level="2"}, {role="row"}, {tabindex="-1"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {role="gridcell"}]
+++++++++TextView text:"Cell 1, row 2, level 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}, {aria-level="2"}, {role="row"}, {tabindex="-1"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {role="gridcell"}]
+++++++++TextView text:"Cell 1, row 3, level 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}, {aria-level="2"}, {role="row"}, {tabindex="-1"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {role="gridcell"}]
+++++++++TextView text:"Cell 1, row 4, level 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}, {aria-level="3"}, {role="row"}, {tabindex="-1"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {role="gridcell"}]
+++++++++TextView text:"Cell 1, row 2, level 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}, {role="treegrid"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tbody"}, {display="table-row-group"}, {role="rowgroup"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}, {aria-level="1"}, {role="row"}, {tabindex="-1"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {role="gridcell"}]
+++++++++++TextView text:"Cell 1, row 1, rowgroup 1, level 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}, {aria-level="1"}, {role="row"}, {tabindex="-1"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {role="gridcell"}]
+++++++++++TextView text:"Cell 1, row 2, rowgroup 1, level 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}, {aria-level="1"}, {role="row"}, {tabindex="-1"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {role="gridcell"}]
+++++++++++TextView text:"Cell 1, row 3, rowgroup 1, level 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}, {aria-level="2"}, {role="row"}, {tabindex="-1"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {role="gridcell"}]
+++++++++++TextView text:"Cell 1, row 1, rowgroup 1, level 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}, {aria-level="1"}, {role="row"}, {tabindex="-1"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {role="gridcell"}]
+++++++++++TextView text:"Cell 1, row 1, rowgroup 1, level 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tbody"}, {display="table-row-group"}, {role="rowgroup"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}, {aria-level="1"}, {role="row"}, {tabindex="-1"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {role="gridcell"}]
+++++++++++TextView text:"Cell 1, row 1, rowgroup 2, level 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {role="gridcell"}]
+++++++++++TextView text:"Cell 2, row 1, rowgroup 2, level 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}, {aria-level="2"}, {role="row"}, {tabindex="-1"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {role="gridcell"}]
+++++++++++TextView text:"Cell 1, row 1, rowgroup 2, level 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {role="gridcell"}]
+++++++++++TextView text:"Cell 2, row 1, rowgroup 2, level 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {role="gridcell"}]
+++++++++++TextView text:"Cell 3, row 1, rowgroup 2, level 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="treegrid"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="rowgroup"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-level="1"}, {role="row"}, {tabindex="-1"}]
+++++++++TextView text:"Cell 1, row 1, rowgroup 1, level 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-level="1"}, {role="row"}, {tabindex="-1"}]
+++++++++TextView text:"Cell 1, row 2, rowgroup 1, level 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-level="1"}, {role="row"}, {tabindex="-1"}]
+++++++++TextView text:"Cell 1, row 3, rowgroup 1, level 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-level="2"}, {role="row"}, {tabindex="-1"}]
+++++++++TextView text:"Cell 1, row 1, rowgroup 1, level 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-level="1"}, {role="row"}, {tabindex="-1"}]
+++++++++TextView text:"Cell 1, row 1, rowgroup 1, level 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="rowgroup"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-level="1"}, {role="row"}, {tabindex="-1"}]
+++++++++TextView text:"Cell 1, row 1, rowgroup 2, level 1 Cell 2, row 1, rowgroup 2, level 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-level="2"}, {role="row"}, {tabindex="-1"}]
+++++++++TextView text:"Cell 1, row 1, rowgroup 2, level 2 Cell 2, row 1, rowgroup 2, level 2 Cell 3, row 1, rowgroup 2, level 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-treeitem-nested-in-lists-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-treeitem-nested-in-lists-expected-android-assist-data.txt
index bae082c5..18ef7be4a 100644
--- a/content/test/data/accessibility/aria/aria-treeitem-nested-in-lists-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-treeitem-nested-in-lists-expected-android-assist-data.txt
@@ -1,31 +1,31 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[class="no-bullets", display="block", htmlTag="ul", role="tree"]
-++++View textSize:16.00 style:0 bundle:[aria-posinset="2", aria-setsize="5", display="block", htmlTag="div", role="treeitem"]
-++++++TextView text:"treeitem 2 of 5, level 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-posinset="3", aria-setsize="5", display="block", htmlTag="div", role="treeitem"]
-++++++TextView text:"treeitem 3 of 5, level 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-level="2", display="block", htmlTag="div", role="treeitem"]
-++++++TextView text:"treeitem 1 of 2, level 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-level="3", display="block", htmlTag="div", role="treeitem"]
-++++++TextView text:"treeitem 1 of 1, level 3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-level="2", display="block", htmlTag="div", role="treeitem"]
-++++++TextView text:"treeitem 2 of 2, level 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", role="tree"]
-++++TextView text:"schedule" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", role="treeitem"]
-++++++TextView text:"• " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"wake up" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", role="treeitem"]
-++++++TextView text:"• " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"drink coffee" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", role="tree"]
-++++++++TextView text:"tasks" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[aria-level="2", display="list-item", htmlTag="li", role="treeitem"]
-++++++++++TextView text:"◦ " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++++TextView text:"meeting" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[aria-level="2", display="list-item", htmlTag="li", role="treeitem"]
-++++++++++TextView text:"◦ " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++++TextView text:"lunch" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", role="treeitem"]
-++++++TextView text:"• " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"cook dinner" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {role="tree"}, {class="no-bullets"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-posinset="2"}, {aria-setsize="5"}, {role="treeitem"}]
+++++++TextView text:"treeitem 2 of 5, level 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-posinset="3"}, {aria-setsize="5"}, {role="treeitem"}]
+++++++TextView text:"treeitem 3 of 5, level 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-level="2"}, {role="treeitem"}]
+++++++TextView text:"treeitem 1 of 2, level 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-level="3"}, {role="treeitem"}]
+++++++TextView text:"treeitem 1 of 1, level 3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-level="2"}, {role="treeitem"}]
+++++++TextView text:"treeitem 2 of 2, level 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {role="tree"}]
+++++TextView text:"schedule" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {role="treeitem"}]
+++++++TextView text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"wake up" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {role="treeitem"}]
+++++++TextView text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"drink coffee" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {role="tree"}]
+++++++++TextView text:"tasks" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-level="2"}, {role="treeitem"}]
+++++++++++TextView text:"◦ " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++++TextView text:"meeting" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-level="2"}, {role="treeitem"}]
+++++++++++TextView text:"◦ " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++++TextView text:"lunch" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {role="treeitem"}]
+++++++TextView text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"cook dinner" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-valuenow-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-valuenow-expected-android-assist-data.txt
index dba14640..5359245c 100644
--- a/content/test/data/accessibility/aria/aria-valuenow-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-valuenow-expected-android-assist-data.txt
@@ -1,2 +1,2 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ProgressBar textSize:16.00 style:0 bundle:[aria-valuenow="3", display="block", htmlTag="div", role="progressbar"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ProgressBar textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-valuenow="3"}, {role="progressbar"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-valuetext-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-valuetext-expected-android-assist-data.txt
index 7a5bc4b..0b2bfa95 100644
--- a/content/test/data/accessibility/aria/aria-valuetext-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-valuetext-expected-android-assist-data.txt
@@ -1,2 +1,2 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ProgressBar text:"three" textSize:16.00 style:0 bundle:[aria-valuemax="96", aria-valuemin="1", aria-valuenow="3", aria-valuetext="three", display="block", htmlTag="div", role="progressbar"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ProgressBar text:"three" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-valuemax="96"}, {aria-valuemin="1"}, {aria-valuenow="3"}, {aria-valuetext="three"}, {role="progressbar"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-virtualcontent-expected-android-assist-data.txt b/content/test/data/accessibility/aria/aria-virtualcontent-expected-android-assist-data.txt
index 38d1d08..a79b74c 100644
--- a/content/test/data/accessibility/aria/aria-virtualcontent-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/aria-virtualcontent-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[aria-virtualcontent="block-end", display="block", htmlTag="div"]
-++++TextView text:"hello world" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-virtualcontent="block-end"}]
+++++TextView text:"hello world" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/dpub-roles-expected-android-assist-data.txt b/content/test/data/accessibility/aria/dpub-roles-expected-android-assist-data.txt
index 021dc1e9..eab6f4a 100644
--- a/content/test/data/accessibility/aria/dpub-roles-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/dpub-roles-expected-android-assist-data.txt
@@ -1,42 +1,42 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View text:"doc-abstract" textSize:16.00 style:0 bundle:[aria-label="doc-abstract", display="block", htmlTag="div", role="doc-abstract"]
-++View text:"doc-acknowledgments" textSize:16.00 style:0 bundle:[aria-label="doc-acknowledgments", display="block", htmlTag="div", role="doc-acknowledgments"]
-++View text:"doc-afterword" textSize:16.00 style:0 bundle:[aria-label="doc-afterword", display="block", htmlTag="div", role="doc-afterword"]
-++View text:"doc-appendix" textSize:16.00 style:0 bundle:[aria-label="doc-appendix", display="block", htmlTag="div", role="doc-appendix"]
-++View text:"doc-backlink" textSize:16.00 style:0 bundle:[aria-label="doc-backlink", display="block", htmlTag="div", role="doc-backlink"]
-++View text:"doc-biblioentry" textSize:16.00 style:0 bundle:[aria-label="doc-biblioentry", display="block", htmlTag="div", role="doc-biblioentry"]
-++View text:"doc-bibliography" textSize:16.00 style:0 bundle:[aria-label="doc-bibliography", display="block", htmlTag="div", role="doc-bibliography"]
-++View text:"doc-biblioref" textSize:16.00 style:0 bundle:[aria-label="doc-biblioref", display="block", htmlTag="div", role="doc-biblioref"]
-++View text:"doc-chapter" textSize:16.00 style:0 bundle:[aria-label="doc-chapter", display="block", htmlTag="div", role="doc-chapter"]
-++View text:"doc-colophon" textSize:16.00 style:0 bundle:[aria-label="doc-colophon", display="block", htmlTag="div", role="doc-colophon"]
-++View text:"doc-conclusion" textSize:16.00 style:0 bundle:[aria-label="doc-conclusion", display="block", htmlTag="div", role="doc-conclusion"]
-++View text:"doc-cover" textSize:16.00 style:0 bundle:[aria-label="doc-cover", display="block", htmlTag="div", role="doc-cover"]
-++View text:"doc-credit" textSize:16.00 style:0 bundle:[aria-label="doc-credit", display="block", htmlTag="div", role="doc-credit"]
-++View text:"doc-credits" textSize:16.00 style:0 bundle:[aria-label="doc-credits", display="block", htmlTag="div", role="doc-credits"]
-++View text:"doc-dedication" textSize:16.00 style:0 bundle:[aria-label="doc-dedication", display="block", htmlTag="div", role="doc-dedication"]
-++View text:"doc-endnote" textSize:16.00 style:0 bundle:[aria-label="doc-endnote", display="block", htmlTag="div", role="doc-endnote"]
-++View text:"doc-endnotes" textSize:16.00 style:0 bundle:[aria-label="doc-endnotes", display="block", htmlTag="div", role="doc-endnotes"]
-++View text:"doc-epigraph" textSize:16.00 style:0 bundle:[aria-label="doc-epigraph", display="block", htmlTag="div", role="doc-epigraph"]
-++View text:"doc-epilogue" textSize:16.00 style:0 bundle:[aria-label="doc-epilogue", display="block", htmlTag="div", role="doc-epilogue"]
-++View text:"doc-errata" textSize:16.00 style:0 bundle:[aria-label="doc-errata", display="block", htmlTag="div", role="doc-errata"]
-++View text:"doc-example" textSize:16.00 style:0 bundle:[aria-label="doc-example", display="block", htmlTag="div", role="doc-example"]
-++View text:"doc-footnote" textSize:16.00 style:0 bundle:[aria-label="doc-footnote", display="block", htmlTag="div", role="doc-footnote"]
-++View text:"doc-foreword" textSize:16.00 style:0 bundle:[aria-label="doc-foreword", display="block", htmlTag="div", role="doc-foreword"]
-++View text:"doc-glossary" textSize:16.00 style:0 bundle:[aria-label="doc-glossary", display="block", htmlTag="div", role="doc-glossary"]
-++View text:"doc-glossref" textSize:16.00 style:0 bundle:[aria-label="doc-glossref", display="block", htmlTag="div", role="doc-glossref"]
-++View text:"doc-index" textSize:16.00 style:0 bundle:[aria-label="doc-index", display="block", htmlTag="div", role="doc-index"]
-++View text:"doc-introduction" textSize:16.00 style:0 bundle:[aria-label="doc-introduction", display="block", htmlTag="div", role="doc-introduction"]
-++View text:"doc-noteref" textSize:16.00 style:0 bundle:[aria-label="doc-noteref", display="block", htmlTag="div", role="doc-noteref"]
-++View text:"doc-notice" textSize:16.00 style:0 bundle:[aria-label="doc-notice", display="block", htmlTag="div", role="doc-notice"]
-++View text:"doc-pagebreak" textSize:16.00 style:0 bundle:[aria-label="doc-pagebreak", display="block", htmlTag="div", role="doc-pagebreak"]
-++View text:"doc-pagefooter" textSize:16.00 style:0 bundle:[aria-label="doc-pagefooter", display="block", htmlTag="div", role="doc-pagefooter"]
-++View text:"doc-pageheader" textSize:16.00 style:0 bundle:[aria-label="doc-pageheader", display="block", htmlTag="div", role="doc-pageheader"]
-++View text:"doc-pagelist" textSize:16.00 style:0 bundle:[aria-label="doc-pagelist", display="block", htmlTag="div", role="doc-pagelist"]
-++View text:"doc-part" textSize:16.00 style:0 bundle:[aria-label="doc-part", display="block", htmlTag="div", role="doc-part"]
-++View text:"doc-preface" textSize:16.00 style:0 bundle:[aria-label="doc-preface", display="block", htmlTag="div", role="doc-preface"]
-++View text:"doc-prologue" textSize:16.00 style:0 bundle:[aria-label="doc-prologue", display="block", htmlTag="div", role="doc-prologue"]
-++View text:"doc-pullquote" textSize:16.00 style:0 bundle:[aria-label="doc-pullquote", display="block", htmlTag="div", role="doc-pullquote"]
-++View text:"doc-qna" textSize:16.00 style:0 bundle:[aria-label="doc-qna", display="block", htmlTag="div", role="doc-qna"]
-++View text:"doc-subtitle" textSize:16.00 style:0 bundle:[aria-label="doc-subtitle", display="block", htmlTag="div", role="doc-subtitle"]
-++View text:"doc-tip" textSize:16.00 style:0 bundle:[aria-label="doc-tip", display="block", htmlTag="div", role="doc-tip"]
-++View text:"doc-toc" textSize:16.00 style:0 bundle:[aria-label="doc-toc", display="block", htmlTag="div", role="doc-toc"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View text:"doc-abstract" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-abstract"}, {role="doc-abstract"}]
+++View text:"doc-acknowledgments" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-acknowledgments"}, {role="doc-acknowledgments"}]
+++View text:"doc-afterword" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-afterword"}, {role="doc-afterword"}]
+++View text:"doc-appendix" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-appendix"}, {role="doc-appendix"}]
+++View text:"doc-backlink" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-backlink"}, {role="doc-backlink"}]
+++View text:"doc-biblioentry" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-biblioentry"}, {role="doc-biblioentry"}]
+++View text:"doc-bibliography" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-bibliography"}, {role="doc-bibliography"}]
+++View text:"doc-biblioref" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-biblioref"}, {role="doc-biblioref"}]
+++View text:"doc-chapter" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-chapter"}, {role="doc-chapter"}]
+++View text:"doc-colophon" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-colophon"}, {role="doc-colophon"}]
+++View text:"doc-conclusion" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-conclusion"}, {role="doc-conclusion"}]
+++View text:"doc-cover" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-cover"}, {role="doc-cover"}]
+++View text:"doc-credit" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-credit"}, {role="doc-credit"}]
+++View text:"doc-credits" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-credits"}, {role="doc-credits"}]
+++View text:"doc-dedication" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-dedication"}, {role="doc-dedication"}]
+++View text:"doc-endnote" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-endnote"}, {role="doc-endnote"}]
+++View text:"doc-endnotes" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-endnotes"}, {role="doc-endnotes"}]
+++View text:"doc-epigraph" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-epigraph"}, {role="doc-epigraph"}]
+++View text:"doc-epilogue" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-epilogue"}, {role="doc-epilogue"}]
+++View text:"doc-errata" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-errata"}, {role="doc-errata"}]
+++View text:"doc-example" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-example"}, {role="doc-example"}]
+++View text:"doc-footnote" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-footnote"}, {role="doc-footnote"}]
+++View text:"doc-foreword" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-foreword"}, {role="doc-foreword"}]
+++View text:"doc-glossary" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-glossary"}, {role="doc-glossary"}]
+++View text:"doc-glossref" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-glossref"}, {role="doc-glossref"}]
+++View text:"doc-index" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-index"}, {role="doc-index"}]
+++View text:"doc-introduction" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-introduction"}, {role="doc-introduction"}]
+++View text:"doc-noteref" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-noteref"}, {role="doc-noteref"}]
+++View text:"doc-notice" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-notice"}, {role="doc-notice"}]
+++View text:"doc-pagebreak" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-pagebreak"}, {role="doc-pagebreak"}]
+++View text:"doc-pagefooter" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-pagefooter"}, {role="doc-pagefooter"}]
+++View text:"doc-pageheader" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-pageheader"}, {role="doc-pageheader"}]
+++View text:"doc-pagelist" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-pagelist"}, {role="doc-pagelist"}]
+++View text:"doc-part" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-part"}, {role="doc-part"}]
+++View text:"doc-preface" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-preface"}, {role="doc-preface"}]
+++View text:"doc-prologue" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-prologue"}, {role="doc-prologue"}]
+++View text:"doc-pullquote" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-pullquote"}, {role="doc-pullquote"}]
+++View text:"doc-qna" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-qna"}, {role="doc-qna"}]
+++View text:"doc-subtitle" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-subtitle"}, {role="doc-subtitle"}]
+++View text:"doc-tip" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-tip"}, {role="doc-tip"}]
+++View text:"doc-toc" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="doc-toc"}, {role="doc-toc"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/graphics-roles-expected-android-assist-data.txt b/content/test/data/accessibility/aria/graphics-roles-expected-android-assist-data.txt
index c604d13..5f9b70c 100644
--- a/content/test/data/accessibility/aria/graphics-roles-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/graphics-roles-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View text:"graphics-document" textSize:16.00 style:0 bundle:[aria-label="graphics-document", display="block", htmlTag="div", role="graphics-document"]
-++View text:"graphics-object" textSize:16.00 style:0 bundle:[aria-label="graphics-object", display="block", htmlTag="div", role="graphics-object"]
-++View text:"graphics-symbol" textSize:16.00 style:0 bundle:[aria-label="graphics-symbol", display="block", htmlTag="div", role="graphics-symbol"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View text:"graphics-document" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="graphics-document"}, {role="graphics-document"}]
+++View text:"graphics-object" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="graphics-object"}, {role="graphics-object"}]
+++View text:"graphics-symbol" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="graphics-symbol"}, {role="graphics-symbol"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/hidden-described-by-expected-android-assist-data.txt b/content/test/data/accessibility/aria/hidden-described-by-expected-android-assist-data.txt
index 0b3a09b..e8bf9f92 100644
--- a/content/test/data/accessibility/aria/hidden-described-by-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/hidden-described-by-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++View text:"span-A3 span-A4" textSize:16.00 style:0 bundle:[aria-describedby="a4", aria-label="span-A3", class="visible", display="inline", htmlTag="span"]
-++++View text:"span-B span-A2" textSize:16.00 style:0 bundle:[aria-describedby="a2", aria-label="span-B", display="inline", htmlTag="span"]
-++++View text:"span-C" textSize:16.00 style:0 bundle:[aria-label="span-C", display="inline", htmlTag="span"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++View text:"span-A3 span-A4" textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-describedby="a4"}, {aria-label="span-A3"}, {class="visible"}]
+++++View text:"span-B span-A2" textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-describedby="a2"}, {aria-label="span-B"}]
+++++View text:"span-C" textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-label="span-C"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/hidden-expected-android-assist-data.txt b/content/test/data/accessibility/aria/hidden-expected-android-assist-data.txt
index 599196a..d05cf25d 100644
--- a/content/test/data/accessibility/aria/hidden-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/hidden-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++View text:"b" textSize:16.00 style:0 bundle:[aria-description="b", display="inline", htmlTag="span"]
-++++View text:"c" textSize:16.00 style:0 bundle:[aria-description="c", display="inline", htmlTag="span"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++View text:"b" textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-description="b"}]
+++++View text:"c" textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-description="c"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/hidden-labelled-by-expected-android-assist-data.txt b/content/test/data/accessibility/aria/hidden-labelled-by-expected-android-assist-data.txt
index 37683926..42d89d1 100644
--- a/content/test/data/accessibility/aria/hidden-labelled-by-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/hidden-labelled-by-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++View text:"span-A4" textSize:16.00 style:0 bundle:[aria-label="span-A3", aria-labelledby="a4", class="visible", display="inline", htmlTag="span", role="group"]
-++++View text:"span-A2" textSize:16.00 style:0 bundle:[aria-label="span-B", aria-labelledby="a2", display="inline", htmlTag="span", role="group"]
-++++View text:"span-C" textSize:16.00 style:0 bundle:[aria-label="span-C", display="inline", htmlTag="span"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++View text:"span-A4" textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-label="span-A3"}, {aria-labelledby="a4"}, {role="group"}, {class="visible"}]
+++++View text:"span-A2" textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-label="span-B"}, {aria-labelledby="a2"}, {role="group"}]
+++++View text:"span-C" textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {aria-label="span-C"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/input-text-aria-placeholder-expected-android-assist-data.txt b/content/test/data/accessibility/aria/input-text-aria-placeholder-expected-android-assist-data.txt
index 1fbe558..51b42505 100644
--- a/content/test/data/accessibility/aria/input-text-aria-placeholder-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/input-text-aria-placeholder-expected-android-assist-data.txt
@@ -1,15 +1,15 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++EditText text:"aria-placeholder1" textSize:13.33 style:0 bundle:[aria-placeholder="aria-placeholder1", display="inline-block", htmlTag="input", type="text"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++EditText text:"placeholder2" textSize:13.33 style:0 bundle:[aria-placeholder="aria-placeholder2", display="inline-block", htmlTag="input", placeholder="placeholder2", type="text"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++EditText text:"aria-label3" textSize:13.33 style:0 bundle:[aria-label="aria-label3", aria-placeholder="aria-placeholder3", display="inline-block", htmlTag="input", placeholder="placeholder3", type="text"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++EditText text:"aria-label4" textSize:13.33 style:0 bundle:[aria-label="aria-label4", aria-placeholder="aria-placeholder4", display="inline-block", htmlTag="input", type="text"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++EditText text:"aria-label5 aria-description5" textSize:13.33 style:0 bundle:[aria-describedby="ariadesc5", aria-label="aria-label5", aria-placeholder="aria-placeholder5", display="inline-block", htmlTag="input", placeholder="placeholder5", type="text"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="ariadesc5"]
-++++TextView text:"aria-description5" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++EditText text:"title6" textSize:13.33 style:0 bundle:[aria-placeholder="aria-placeholder6", display="inline-block", htmlTag="input", title="title6", type="text"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++EditText text:"aria-placeholder1" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-placeholder="aria-placeholder1"}, {type="text"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++EditText text:"placeholder2" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-placeholder="aria-placeholder2"}, {placeholder="placeholder2"}, {type="text"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++EditText text:"aria-label3" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-label="aria-label3"}, {aria-placeholder="aria-placeholder3"}, {placeholder="placeholder3"}, {type="text"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++EditText text:"aria-label4" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-label="aria-label4"}, {aria-placeholder="aria-placeholder4"}, {type="text"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++EditText text:"aria-label5 aria-description5" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-describedby="ariadesc5"}, {aria-label="aria-label5"}, {aria-placeholder="aria-placeholder5"}, {placeholder="placeholder5"}, {type="text"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="ariadesc5"}]
+++++TextView text:"aria-description5" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++EditText text:"title6" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-placeholder="aria-placeholder6"}, {title="title6"}, {type="text"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/presentational-expected-android-assist-data.txt b/content/test/data/accessibility/aria/presentational-expected-android-assist-data.txt
index 2538d91..2eb5f4f 100644
--- a/content/test/data/accessibility/aria/presentational-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/presentational-expected-android-assist-data.txt
@@ -1,9 +1,9 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="section"]
-++++View textSize:24.00 style:1 bundle:[display="block", htmlTag="h2"]
-++++++TextView text:"Heading " textSize:24.00 style:1 bundle:[display="", htmlTag=""]
-++++++View textSize:24.00 style:5 fgColor:-16776978 bundle:[display="inline", href="#", htmlTag="a"]
-++++++++TextView text:"with link" textSize:24.00 style:5 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++TextView text:"Presentational heading " textSize:24.00 style:1 bundle:[display="", htmlTag=""]
-++++View textSize:24.00 style:5 fgColor:-16776978 bundle:[display="inline", href="#", htmlTag="a"]
-++++++TextView text:"with link" textSize:24.00 style:5 fgColor:-16776978 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="section"}, {display="block"}]
+++++View textSize:24.0 style:1 htmlInfo:[{htmlTag="h2"}, {display="block"}]
+++++++TextView text:"Heading " textSize:24.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:24.0 style:5 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#"}]
+++++++++TextView text:"with link" textSize:24.0 style:5 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"Presentational heading " textSize:24.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:24.0 style:5 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#"}]
+++++++TextView text:"with link" textSize:24.0 style:5 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/toggle-button-expand-collapse-expected-android-assist-data.txt b/content/test/data/accessibility/aria/toggle-button-expand-collapse-expected-android-assist-data.txt
index 08f7c9c5..607032a 100644
--- a/content/test/data/accessibility/aria/toggle-button-expand-collapse-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/aria/toggle-button-expand-collapse-expected-android-assist-data.txt
@@ -1,9 +1,9 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ToggleButton textSize:16.00 style:0 bundle:[aria-expanded="false", aria-haspopup="true", aria-pressed="true", display="block", htmlTag="div", role="button"]
-++++TextView text:"Toggle button, pressed, collapsed" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ToggleButton textSize:16.00 style:0 bundle:[aria-expanded="false", aria-haspopup="true", aria-pressed="false", display="block", htmlTag="div", role="button"]
-++++TextView text:"Toggle button, not pressed, collapsed" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ToggleButton textSize:16.00 style:0 bundle:[aria-expanded="true", aria-haspopup="true", aria-pressed="true", display="block", htmlTag="div", role="button"]
-++++TextView text:"Toggle button, pressed, expanded" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ToggleButton textSize:16.00 style:0 bundle:[aria-expanded="true", aria-haspopup="true", aria-pressed="false", display="block", htmlTag="div", role="button"]
-++++TextView text:"Toggle button, not pressed, collapsed"" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ToggleButton textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-expanded="false"}, {aria-haspopup="true"}, {aria-pressed="true"}, {role="button"}]
+++++TextView text:"Toggle button, pressed, collapsed" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ToggleButton textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-expanded="false"}, {aria-haspopup="true"}, {aria-pressed="false"}, {role="button"}]
+++++TextView text:"Toggle button, not pressed, collapsed" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ToggleButton textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-expanded="true"}, {aria-haspopup="true"}, {aria-pressed="true"}, {role="button"}]
+++++TextView text:"Toggle button, pressed, expanded" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ToggleButton textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-expanded="true"}, {aria-haspopup="true"}, {aria-pressed="false"}, {role="button"}]
+++++TextView text:"Toggle button, not pressed, collapsed"" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/css/alt-text-expected-android-assist-data.txt b/content/test/data/accessibility/css/alt-text-expected-android-assist-data.txt
index dba62cd..ffe2980 100644
--- a/content/test/data/accessibility/css/alt-text-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/css/alt-text-expected-android-assist-data.txt
@@ -1,44 +1,44 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="controlparent"]
-++++TextView text:"item1item2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++Image textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="controlchild"]
-++++++TextView text:"Some Text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="parent"]
-++++TextView text:"code" textSize:16.00 style:0 bundle:[display="", htmlTag="::before"]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="child"]
-++++++TextView text:"Some Text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="parentempty"]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="childempty"]
-++++++TextView text:"Some Text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[class="title", display="block", htmlTag="div", id="imgparent"]
-++++Image text:"star" textSize:16.00 style:0 bundle:[display="inline", htmlTag="::before"]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="imgchild"]
-++++++TextView text:"Some Text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[class="title", display="block", htmlTag="div", id="imgparentempty"]
-++++Image textSize:16.00 style:0 bundle:[display="inline", htmlTag="::before"]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="imgchildempty"]
-++++++TextView text:"Some Text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[class="title", display="block", htmlTag="div", id="divlistparent"]
-++++TextView text:"a list of items" textSize:16.00 style:0 bundle:[display="", htmlTag="::before"]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="divlistchild"]
-++++++TextView text:"Some Text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[class="title", display="block", htmlTag="div", id="emptylistparent"]
-++++Image textSize:16.00 style:0 bundle:[display="inline", htmlTag="::before"]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="emptylistchild"]
-++++++TextView text:"Some Text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="firstletterparent"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p", id="firstletterchild"]
-++++++TextView text:"Some Text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++Image text:"alt" textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="divcontent"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="divdoubleimage"]
-++++TextView text:"DOM Text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="divtextcontent"]
-++++TextView text:"DOM Text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="controlparent"}]
+++++TextView text:"item1item2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="controlchild"}]
+++++++TextView text:"Some Text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="parent"}]
+++++TextView text:"code" textSize:16.0 style:0 htmlInfo:[{htmlTag="::before"}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="child"}]
+++++++TextView text:"Some Text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="parentempty"}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="childempty"}]
+++++++TextView text:"Some Text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="imgparent"}, {class="title"}]
+++++Image text:"star" textSize:16.0 style:0 htmlInfo:[{htmlTag="::before"}, {display="inline"}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="imgchild"}]
+++++++TextView text:"Some Text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="imgparentempty"}, {class="title"}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="::before"}, {display="inline"}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="imgchildempty"}]
+++++++TextView text:"Some Text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="divlistparent"}, {class="title"}]
+++++TextView text:"a list of items" textSize:16.0 style:0 htmlInfo:[{htmlTag="::before"}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="divlistchild"}]
+++++++TextView text:"Some Text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="emptylistparent"}, {class="title"}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="::before"}, {display="inline"}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="emptylistchild"}]
+++++++TextView text:"Some Text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="firstletterparent"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {id="firstletterchild"}]
+++++++TextView text:"Some Text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Image text:"alt" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="divcontent"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="divdoubleimage"}]
+++++TextView text:"DOM Text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="divtextcontent"}]
+++++TextView text:"DOM Text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/css/background-color-transparent-expected-android-assist-data.txt b/content/test/data/accessibility/css/background-color-transparent-expected-android-assist-data.txt
index baa03ecf..0c42c867 100644
--- a/content/test/data/accessibility/css/background-color-transparent-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/css/background-color-transparent-expected-android-assist-data.txt
@@ -1,11 +1,11 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="default"]
-++++TextView text:"Document base color." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p", id="transparent", style="background-color: transparent"]
-++++TextView text:"Transparent color." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p", id="obscuring-background", style="background-color: transparent"]
-++++TextView text:"Obscuring background." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bgColor:-2139062144 bundle:[display="block", htmlTag="p", id="blended-default", style="background-color: rgba(50%, 50%, 50%, 0.5)"]
-++++TextView text:"Blended with document base color." textSize:16.00 style:0 bgColor:-2139062144 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bgColor:-2139062144 bundle:[display="block", htmlTag="p", id="blended-background", style="background-color: rgba(50%, 50%, 50%, 0.5)"]
-++++TextView text:"Blended with background color." textSize:16.00 style:0 bgColor:-2139062144 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="default"}]
+++++TextView text:"Document base color." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {id="transparent"}, {style="background-color: transparent"}]
+++++TextView text:"Transparent color." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {id="obscuring-background"}, {style="background-color: transparent"}]
+++++TextView text:"Obscuring background." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 bgColor:-2139062144 htmlInfo:[{htmlTag="p"}, {display="block"}, {id="blended-default"}, {style="background-color: rgba(50%, 50%, 50%, 0.5)"}]
+++++TextView text:"Blended with document base color." textSize:16.0 style:0 bgColor:-2139062144 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 bgColor:-2139062144 htmlInfo:[{htmlTag="p"}, {display="block"}, {id="blended-background"}, {style="background-color: rgba(50%, 50%, 50%, 0.5)"}]
+++++TextView text:"Blended with background color." textSize:16.0 style:0 bgColor:-2139062144 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/css/before-after-code-expected-android-assist-data.txt b/content/test/data/accessibility/css/before-after-code-expected-android-assist-data.txt
index 06fca687..58dc9bde 100644
--- a/content/test/data/accessibility/css/before-after-code-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/css/before-after-code-expected-android-assist-data.txt
@@ -1,27 +1,27 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++TextView text:"start" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++TextView text:"text with " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"[" textSize:13.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:":before" textSize:13.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"]" textSize:13.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" and " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"[" textSize:13.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:":after" textSize:13.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"]" textSize:13.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" content, then a" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"bold" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++TextView text:" element with a " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"[" textSize:13.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"block" textSize:13.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"]" textSize:13.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" before content then a " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"italic" textSize:16.00 style:2 bundle:[display="", htmlTag=""]
-++++TextView text:"element with a " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"[" textSize:13.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"block" textSize:13.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"]" textSize:13.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" after content" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++TextView text:"end" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++TextView text:"start" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++TextView text:"text with " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"[" textSize:13.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:":before" textSize:13.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"]" textSize:13.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" and " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"[" textSize:13.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:":after" textSize:13.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"]" textSize:13.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" content, then a" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"bold" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" element with a " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"[" textSize:13.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"block" textSize:13.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"]" textSize:13.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" before content then a " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"italic" textSize:16.0 style:2 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"element with a " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"[" textSize:13.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"block" textSize:13.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"]" textSize:13.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" after content" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++TextView text:"end" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/css/color-expected-android-assist-data.txt b/content/test/data/accessibility/css/color-expected-android-assist-data.txt
index e4861c15..49b0e79 100644
--- a/content/test/data/accessibility/css/color-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/css/color-expected-android-assist-data.txt
@@ -1,9 +1,9 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 fgColor:-65536 bgColor:-16776961 bundle:[display="block", htmlTag="p", style="background-color: #0000FF; color: #FF0000"]
-++++TextView text:"Red on blue." textSize:16.00 style:0 fgColor:-65536 bgColor:-16776961 bundle:[display="", htmlTag=""]
-++View text:"Default. Blue background. Green text." textSize:16.00 style:0 bundle:[contenteditable="", display="block", htmlTag="div"]
-++++TextView text:"Default." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"Blue background." textSize:16.00 style:0 bgColor:-16776961 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"Green text." textSize:16.00 style:0 fgColor:-16711936 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 fgColor:-65536 bgColor:-16776961 htmlInfo:[{htmlTag="p"}, {display="block"}, {style="background-color: #0000FF; color: #FF0000"}]
+++++TextView text:"Red on blue." textSize:16.0 style:0 fgColor:-65536 bgColor:-16776961 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"Default. Blue background. Green text." textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {contenteditable=""}]
+++++TextView text:"Default." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"Blue background." textSize:16.0 style:0 bgColor:-16776961 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"Green text." textSize:16.0 style:0 fgColor:-16711936 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/css/dom-element-css-alternative-text-expected-android-assist-data.txt b/content/test/data/accessibility/css/dom-element-css-alternative-text-expected-android-assist-data.txt
index 57b5d222..3c4d8bd 100644
--- a/content/test/data/accessibility/css/dom-element-css-alternative-text-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/css/dom-element-css-alternative-text-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Image text:"alternative text" textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="element"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Image text:"alternative text" textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="element"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/css/font-size-expected-android-assist-data.txt b/content/test/data/accessibility/css/font-size-expected-android-assist-data.txt
index ac3ddc4..6050d0e5 100644
--- a/content/test/data/accessibility/css/font-size-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/css/font-size-expected-android-assist-data.txt
@@ -1,45 +1,45 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:10.23 style:0 bundle:[display="block", htmlTag="p", style="font-size: 10.2340920823px"]
-++++TextView text:"10.2340920823px" textSize:10.23 style:0 bundle:[display="", htmlTag=""]
-++View textSize:10.00 style:0 bundle:[display="block", htmlTag="p", style="font-size: 10px"]
-++++TextView text:"10px" textSize:10.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:11.00 style:0 bundle:[display="block", htmlTag="p", style="font-size: 11px"]
-++++TextView text:"11px" textSize:11.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:12.00 style:0 bundle:[display="block", htmlTag="p", style="font-size: 12px"]
-++++TextView text:"12px" textSize:12.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:13.00 style:0 bundle:[display="block", htmlTag="p", style="font-size: 13px"]
-++++TextView text:"13px" textSize:13.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:14.00 style:0 bundle:[display="block", htmlTag="p", style="font-size: 14px"]
-++++TextView text:"14px" textSize:14.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:15.00 style:0 bundle:[display="block", htmlTag="p", style="font-size: 15px"]
-++++TextView text:"15px" textSize:15.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:20.00 style:0 bundle:[display="block", htmlTag="p", style="font-size: 20px"]
-++++TextView text:"20px" textSize:20.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:40.00 style:0 bundle:[display="block", htmlTag="p", style="font-size: 40px"]
-++++TextView text:"40px" textSize:40.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:50.00 style:0 bundle:[display="block", htmlTag="p", style="font-size: 50px"]
-++++TextView text:"50px" textSize:50.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:100.00 style:0 bundle:[display="block", htmlTag="p", style="font-size: 100px"]
-++++TextView text:"100px" textSize:100.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:13.65 style:0 bundle:[display="block", htmlTag="p", style="font-size: 10.2340920823pt"]
-++++TextView text:"10.2340920823pt" textSize:13.65 style:0 bundle:[display="", htmlTag=""]
-++View textSize:13.33 style:0 bundle:[display="block", htmlTag="p", style="font-size: 10pt"]
-++++TextView text:"10pt" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++View textSize:14.67 style:0 bundle:[display="block", htmlTag="p", style="font-size: 11pt"]
-++++TextView text:"11pt" textSize:14.67 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p", style="font-size: 12pt"]
-++++TextView text:"12pt" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:17.33 style:0 bundle:[display="block", htmlTag="p", style="font-size: 13pt"]
-++++TextView text:"13pt" textSize:17.33 style:0 bundle:[display="", htmlTag=""]
-++View textSize:18.67 style:0 bundle:[display="block", htmlTag="p", style="font-size: 14pt"]
-++++TextView text:"14pt" textSize:18.67 style:0 bundle:[display="", htmlTag=""]
-++View textSize:20.00 style:0 bundle:[display="block", htmlTag="p", style="font-size: 15pt"]
-++++TextView text:"15pt" textSize:20.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:26.67 style:0 bundle:[display="block", htmlTag="p", style="font-size: 20pt"]
-++++TextView text:"20pt" textSize:26.67 style:0 bundle:[display="", htmlTag=""]
-++View textSize:53.33 style:0 bundle:[display="block", htmlTag="p", style="font-size: 40pt"]
-++++TextView text:"40pt" textSize:53.33 style:0 bundle:[display="", htmlTag=""]
-++View textSize:66.67 style:0 bundle:[display="block", htmlTag="p", style="font-size: 50pt"]
-++++TextView text:"50pt" textSize:66.67 style:0 bundle:[display="", htmlTag=""]
-++View textSize:133.33 style:0 bundle:[display="block", htmlTag="p", style="font-size: 100pt"]
-++++TextView text:"100pt" textSize:133.33 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:10.2 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {style="font-size: 10.2340920823px"}]
+++++TextView text:"10.2340920823px" textSize:10.2 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:10.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {style="font-size: 10px"}]
+++++TextView text:"10px" textSize:10.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:11.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {style="font-size: 11px"}]
+++++TextView text:"11px" textSize:11.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:12.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {style="font-size: 12px"}]
+++++TextView text:"12px" textSize:12.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:13.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {style="font-size: 13px"}]
+++++TextView text:"13px" textSize:13.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:14.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {style="font-size: 14px"}]
+++++TextView text:"14px" textSize:14.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:15.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {style="font-size: 15px"}]
+++++TextView text:"15px" textSize:15.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:20.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {style="font-size: 20px"}]
+++++TextView text:"20px" textSize:20.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:40.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {style="font-size: 40px"}]
+++++TextView text:"40px" textSize:40.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:50.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {style="font-size: 50px"}]
+++++TextView text:"50px" textSize:50.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:100.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {style="font-size: 100px"}]
+++++TextView text:"100px" textSize:100.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:13.6 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {style="font-size: 10.2340920823pt"}]
+++++TextView text:"10.2340920823pt" textSize:13.6 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:13.3 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {style="font-size: 10pt"}]
+++++TextView text:"10pt" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:14.7 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {style="font-size: 11pt"}]
+++++TextView text:"11pt" textSize:14.7 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {style="font-size: 12pt"}]
+++++TextView text:"12pt" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:17.3 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {style="font-size: 13pt"}]
+++++TextView text:"13pt" textSize:17.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:18.7 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {style="font-size: 14pt"}]
+++++TextView text:"14pt" textSize:18.7 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:20.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {style="font-size: 15pt"}]
+++++TextView text:"15pt" textSize:20.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:26.7 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {style="font-size: 20pt"}]
+++++TextView text:"20pt" textSize:26.7 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:53.3 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {style="font-size: 40pt"}]
+++++TextView text:"40pt" textSize:53.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:66.7 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {style="font-size: 50pt"}]
+++++TextView text:"50pt" textSize:66.7 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:133.3 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {style="font-size: 100pt"}]
+++++TextView text:"100pt" textSize:133.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/css/font-style-expected-android-assist-data.txt b/content/test/data/accessibility/css/font-style-expected-android-assist-data.txt
index 799123f..620f18d 100644
--- a/content/test/data/accessibility/css/font-style-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/css/font-style-expected-android-assist-data.txt
@@ -1,28 +1,28 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"The " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"quick" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"brown" textSize:16.00 style:2 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"fox" textSize:16.00 style:4 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"jumped" textSize:16.00 style:3 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"over" textSize:16.00 style:6 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"dog" textSize:16.00 style:7 bundle:[display="", htmlTag=""]
-++View text:"Normal bold italic underline line-through subscript superscript" textSize:16.00 style:0 bundle:[contenteditable="", display="block", htmlTag="div"]
-++++TextView text:"Normal" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"bold" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"italic" textSize:16.00 style:2 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"underline" textSize:16.00 style:4 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"line-through" textSize:16.00 style:8 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"subscript" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"superscript" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"The " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"quick" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"brown" textSize:16.0 style:2 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"fox" textSize:16.0 style:4 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"jumped" textSize:16.0 style:3 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"over" textSize:16.0 style:6 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"dog" textSize:16.0 style:7 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"Normal bold italic underline line-through subscript superscript" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {contenteditable=""}]
+++++TextView text:"Normal" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"bold" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"italic" textSize:16.0 style:2 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"underline" textSize:16.0 style:4 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"line-through" textSize:16.0 style:8 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"subscript" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"superscript" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/css/language-expected-android-assist-data.txt b/content/test/data/accessibility/css/language-expected-android-assist-data.txt
index 4c40f859..c3ed5dcb 100644
--- a/content/test/data/accessibility/css/language-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/css/language-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p", lang="es-ES"]
-++++TextView text:"Espanyol" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++TextView text:"Comment allez-vous?" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {lang="es-ES"}]
+++++TextView text:"Espanyol" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++TextView text:"Comment allez-vous?" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/css/list-marker-styles-custom-expected-android-assist-data.txt b/content/test/data/accessibility/css/list-marker-styles-custom-expected-android-assist-data.txt
index d7b77821..f9431ba9 100644
--- a/content/test/data/accessibility/css/list-marker-styles-custom-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/css/list-marker-styles-custom-expected-android-assist-data.txt
@@ -1,125 +1,125 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", style="list-style-type: disc"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"• " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"disc" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", style="list-style-type: circle"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"◦ " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"circle" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", style="list-style-type: square"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"■ " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"square" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", style="list-style-type: disclosure-open"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"▾ " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"disclosure-open" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", style="list-style-type: disclosure-closed"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"▸ " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"disclosure-closed" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", style="list-style-type: explicit-bullets"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"One. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"explicit-bullets" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"Two. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"Three. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", style="list-style-type: explicit-numbers"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"One. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"explicit-numbers" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"Two. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"Three. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", style="list-style-type: explicit-words"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"One. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"explicit-words" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"Two. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"Three. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", style="list-style-type: auto-alphabetic"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"One. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"auto-alphabetic" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"Two. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"Three. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", style="list-style-type: auto-cyclic"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"One. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"auto-cyclic" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"Two. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"Three. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", style="list-style-type: auto-extends"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"One. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"auto-extends" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"Two. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"Three. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", style="list-style-type: auto-fixed"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"One. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"auto-fixed" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"Two. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"Three. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", style="list-style-type: auto-symbolic"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"One. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"auto-symbolic" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"Two. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"Three. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", style="list-style-type: auto-numeric"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"One. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"auto-numeric" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"Two. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"Three. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", style="list-style-type: auto-additive"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"One. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"auto-additive" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"Two. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"Three. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", style="list-style-type: reference-bullets"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"Yi> " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"reference-bullets" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"Er> " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"San> " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", style="list-style-type: reference-numbers"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"Yi> " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"reference-numbers" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"Er> " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"San> " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", style="list-style-type: reference-words"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"Yi> " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"reference-words" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"Er> " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"San> " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {style="list-style-type: disc"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"disc" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {style="list-style-type: circle"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"◦ " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"circle" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {style="list-style-type: square"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"■ " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"square" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {style="list-style-type: disclosure-open"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"▾ " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"disclosure-open" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {style="list-style-type: disclosure-closed"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"▸ " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"disclosure-closed" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {style="list-style-type: explicit-bullets"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"One. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"explicit-bullets" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"Two. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"Three. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {style="list-style-type: explicit-numbers"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"One. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"explicit-numbers" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"Two. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"Three. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {style="list-style-type: explicit-words"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"One. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"explicit-words" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"Two. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"Three. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {style="list-style-type: auto-alphabetic"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"One. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"auto-alphabetic" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"Two. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"Three. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {style="list-style-type: auto-cyclic"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"One. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"auto-cyclic" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"Two. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"Three. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {style="list-style-type: auto-extends"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"One. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"auto-extends" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"Two. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"Three. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {style="list-style-type: auto-fixed"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"One. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"auto-fixed" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"Two. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"Three. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {style="list-style-type: auto-symbolic"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"One. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"auto-symbolic" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"Two. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"Three. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {style="list-style-type: auto-numeric"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"One. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"auto-numeric" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"Two. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"Three. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {style="list-style-type: auto-additive"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"One. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"auto-additive" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"Two. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"Three. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {style="list-style-type: reference-bullets"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"Yi> " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"reference-bullets" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"Er> " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"San> " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {style="list-style-type: reference-numbers"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"Yi> " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"reference-numbers" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"Er> " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"San> " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {style="list-style-type: reference-words"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"Yi> " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"reference-words" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"Er> " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"San> " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/css/pseudo-element-alternative-text-expected-android-assist-data.txt b/content/test/data/accessibility/css/pseudo-element-alternative-text-expected-android-assist-data.txt
index bdb1995..4d60c34 100644
--- a/content/test/data/accessibility/css/pseudo-element-alternative-text-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/css/pseudo-element-alternative-text-expected-android-assist-data.txt
@@ -1,7 +1,7 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="parent"]
-++++Image text:"alternative text" textSize:16.00 style:0 bundle:[display="inline", htmlTag="::before"]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"DOM text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++Image textSize:16.00 style:0 bundle:[display="inline", htmlTag="::after"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="parent"}]
+++++Image text:"alternative text" textSize:16.0 style:0 htmlInfo:[{htmlTag="::before"}, {display="inline"}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"DOM text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="::after"}, {display="inline"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/css/pseudo-element-positioned-expected-android-assist-data.txt b/content/test/data/accessibility/css/pseudo-element-positioned-expected-android-assist-data.txt
index a4485d2..d60220f6 100644
--- a/content/test/data/accessibility/css/pseudo-element-positioned-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/css/pseudo-element-positioned-expected-android-assist-data.txt
@@ -1,9 +1,9 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++TextView text:"Empty before and after" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[class="positioned", display="block", htmlTag="div"]
-++++TextView text:"Empty positioned before and after" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="::before"]
-++++TextView text:"pseudo" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++TextView text:"Positioned before and after with content" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="::after"]
-++++TextView text:"pseudo" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++TextView text:"Empty before and after" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {class="positioned"}]
+++++TextView text:"Empty positioned before and after" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="::before"}, {display="block"}]
+++++TextView text:"pseudo" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++TextView text:"Positioned before and after with content" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="::after"}, {display="block"}]
+++++TextView text:"pseudo" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/css/pseudo-elements-expected-android-assist-data.txt b/content/test/data/accessibility/css/pseudo-elements-expected-android-assist-data.txt
index 13f62e6..731114a5 100644
--- a/content/test/data/accessibility/css/pseudo-elements-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/css/pseudo-elements-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:32.00 style:1 bundle:[class="generated", display="block", htmlTag="h1"]
-++++TextView text:"[ " textSize:32.00 style:1 bundle:[display="", htmlTag=""]
-++++TextView text:"Foo" textSize:32.00 style:1 bundle:[display="", htmlTag=""]
-++++TextView text:" ]" textSize:32.00 style:1 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:32.0 style:1 htmlInfo:[{htmlTag="h1"}, {display="block"}, {class="generated"}]
+++++TextView text:"[ " textSize:32.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"Foo" textSize:32.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" ]" textSize:32.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/a-expected-android-assist-data.txt b/content/test/data/accessibility/html/a-expected-android-assist-data.txt
index dab0b8e..b50bad0 100644
--- a/content/test/data/accessibility/html/a-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/a-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="http://www.google.com", htmlTag="a"]
-++++++TextView text:"normal link" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="http://www.google.com"}]
+++++++TextView text:"normal link" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/a-name-calc-expected-android-assist-data.txt b/content/test/data/accessibility/html/a-name-calc-expected-android-assist-data.txt
index fd063cb..d3b346a 100644
--- a/content/test/data/accessibility/html/a-name-calc-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/a-name-calc-expected-android-assist-data.txt
@@ -1,21 +1,21 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#", htmlTag="a"]
-++++TextView text:"InnerText0" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#", htmlTag="a", title="Title1"]
-++++TextView text:"InnerText1" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"Title2" textSize:16.00 style:4 fgColor:-16776978 bundle:[aria-label="Title2", display="inline", href="#", htmlTag="a"]
-++++TextView text:"InnerText2" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"LabelledBy3" textSize:16.00 style:4 fgColor:-16776978 bundle:[aria-labelledby="label3", display="inline", href="#", htmlTag="a"]
-++++TextView text:"InnerText3" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++View text:"Title4" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#", htmlTag="a", title="Title4"]
-++View text:"Label5" textSize:16.00 style:4 fgColor:-16776978 bundle:[aria-label="Label5", display="inline", href="#", htmlTag="a"]
-++View text:"LabelledBy6" textSize:16.00 style:4 fgColor:-16776978 bundle:[aria-labelledby="label6", display="inline", href="#", htmlTag="a"]
-++View textSize:16.00 style:0 bundle:[class="@NO_DUMP", display="block", htmlTag="p"]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="label3"]
-++++++TextView text:"LabelledBy3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="label6"]
-++++++TextView text:"LabelledBy6" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#"}]
+++++TextView text:"InnerText0" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#"}, {title="Title1"}]
+++++TextView text:"InnerText1" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"Title2" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {aria-label="Title2"}, {href="#"}]
+++++TextView text:"InnerText2" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"LabelledBy3" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {aria-labelledby="label3"}, {href="#"}]
+++++TextView text:"InnerText3" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"Title4" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#"}, {title="Title4"}]
+++View text:"Label5" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {aria-label="Label5"}, {href="#"}]
+++View text:"LabelledBy6" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {aria-labelledby="label6"}, {href="#"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {class="@NO_DUMP"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="label3"}]
+++++++TextView text:"LabelledBy3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="label6"}]
+++++++TextView text:"LabelledBy6" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/a-name-expected-android-assist-data.txt b/content/test/data/accessibility/html/a-name-expected-android-assist-data.txt
index c37ad4f..6521e2c 100644
--- a/content/test/data/accessibility/html/a-name-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/a-name-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:4 bundle:[display="block", htmlTag="a", name="named_anchor_1"]
-++++TextView text:"named anchor" textSize:16.00 style:4 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="block", href="#foo", htmlTag="a", name="named_anchor_2"]
-++++TextView text:"both a named anchor and a link" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:4 htmlInfo:[{htmlTag="a"}, {display="block"}, {name="named_anchor_1"}]
+++++TextView text:"named anchor" textSize:16.0 style:4 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="block"}, {href="#foo"}, {name="named_anchor_2"}]
+++++TextView text:"both a named anchor and a link" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/a-nested-structure-expected-android-assist-data.txt b/content/test/data/accessibility/html/a-nested-structure-expected-android-assist-data.txt
index 90e5e592..86f2d8b 100644
--- a/content/test/data/accessibility/html/a-nested-structure-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/a-nested-structure-expected-android-assist-data.txt
@@ -1,15 +1,15 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="http://www.foobar.com", htmlTag="a"]
-++++++View textSize:32.00 style:5 fgColor:-16776978 bundle:[display="block", htmlTag="h1"]
-++++++++TextView text:"Header 1" textSize:32.00 style:5 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++++ListView textSize:16.00 style:4 fgColor:-16776978 bundle:[display="block", htmlTag="ul"]
-++++++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="list-item", htmlTag="li"]
-++++++++++View text:"• " textSize:16.00 style:0 fgColor:-16776978 bundle:[display="inline-block", htmlTag="::marker"]
-++++++++++TextView text:"List element 1" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="list-item", htmlTag="li"]
-++++++++++View text:"• " textSize:16.00 style:0 fgColor:-16776978 bundle:[display="inline-block", htmlTag="::marker"]
-++++++++++TextView text:"List element 2" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="list-item", htmlTag="li"]
-++++++++++View text:"• " textSize:16.00 style:0 fgColor:-16776978 bundle:[display="inline-block", htmlTag="::marker"]
-++++++++++TextView text:"List element 3" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="http://www.foobar.com"}]
+++++++View textSize:32.0 style:5 fgColor:-16776978 htmlInfo:[{htmlTag="h1"}, {display="block"}]
+++++++++TextView text:"Header 1" textSize:32.0 style:5 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++ListView textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="ul"}, {display="block"}]
+++++++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++++++View text:"• " textSize:16.0 style:0 fgColor:-16776978 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++++++TextView text:"List element 1" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++++++View text:"• " textSize:16.0 style:0 fgColor:-16776978 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++++++TextView text:"List element 2" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++++++View text:"• " textSize:16.0 style:0 fgColor:-16776978 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++++++TextView text:"List element 3" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/a-no-text-expected-android-assist-data.txt b/content/test/data/accessibility/html/a-no-text-expected-android-assist-data.txt
index eb965a47..9a6b57c 100644
--- a/content/test/data/accessibility/html/a-no-text-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/a-no-text-expected-android-assist-data.txt
@@ -1,23 +1,23 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++View text:"dest1" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="dest1", htmlTag="a"]
-++++++Image textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", htmlTag="img", src=""]
-++++View text:"dest2" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="/dest2", htmlTag="a"]
-++++++Image textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", htmlTag="img", src=""]
-++++View text:"dest3" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="dest3/", htmlTag="a"]
-++++++Image textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", htmlTag="img", src=""]
-++++View text:"dest4" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="http://example.com/dest4", htmlTag="a"]
-++++++Image textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", htmlTag="img", src=""]
-++++View text:"dest5" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="http://example.com/dest5/", htmlTag="a"]
-++++++Image textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", htmlTag="img", src=""]
-++++View text:"dest6" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="dest6.html", htmlTag="a"]
-++++++Image textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", htmlTag="img", src=""]
-++++View text:"dest7" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="http://example.com/dest7.html", htmlTag="a"]
-++++++Image textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", htmlTag="img", src=""]
-++++View text:"dest.8" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="http://example.com/dest.8.html", htmlTag="a"]
-++++++Image textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", htmlTag="img", src=""]
-++++View text:"dest9" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="dest9.html", htmlTag="a"]
-++++++Image text:"greenbox" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", htmlTag="img", src="greenbox.png"]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View text:"dest10" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="dest10.html", htmlTag="a"]
-++++++Image text:"greenbox" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", htmlTag="img", src="greenbox.png"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++View text:"dest1" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="dest1"}]
+++++++Image textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="img"}, {display="inline"}, {src=""}]
+++++View text:"dest2" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="/dest2"}]
+++++++Image textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="img"}, {display="inline"}, {src=""}]
+++++View text:"dest3" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="dest3/"}]
+++++++Image textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="img"}, {display="inline"}, {src=""}]
+++++View text:"dest4" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="http://example.com/dest4"}]
+++++++Image textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="img"}, {display="inline"}, {src=""}]
+++++View text:"dest5" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="http://example.com/dest5/"}]
+++++++Image textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="img"}, {display="inline"}, {src=""}]
+++++View text:"dest6" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="dest6.html"}]
+++++++Image textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="img"}, {display="inline"}, {src=""}]
+++++View text:"dest7" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="http://example.com/dest7.html"}]
+++++++Image textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="img"}, {display="inline"}, {src=""}]
+++++View text:"dest.8" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="http://example.com/dest.8.html"}]
+++++++Image textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="img"}, {display="inline"}, {src=""}]
+++++View text:"dest9" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="dest9.html"}]
+++++++Image text:"greenbox" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="img"}, {display="inline"}, {src="greenbox.png"}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View text:"dest10" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="dest10.html"}]
+++++++Image text:"greenbox" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="img"}, {display="inline"}, {src="greenbox.png"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/a-with-img-expected-android-assist-data.txt b/content/test/data/accessibility/html/a-with-img-expected-android-assist-data.txt
index 4b83765..183e00c 100644
--- a/content/test/data/accessibility/html/a-with-img-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/a-with-img-expected-android-assist-data.txt
@@ -1,19 +1,19 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="http://www.google.com", htmlTag="a"]
-++++++Image text:"Link" textSize:16.00 style:4 fgColor:-16776978 bundle:[alt="Link", display="inline", htmlTag="img", src="bullet.png"]
-++++++TextView text:" with image at start." textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="http://www.google.com", htmlTag="a"]
-++++++TextView text:"Link with " textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++++Image text:"bullet image" textSize:16.00 style:4 fgColor:-16776978 bundle:[alt="bullet image", display="inline", htmlTag="img", src="bullet.png"]
-++++++TextView text:" in the middle." textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="http://www.google.com", htmlTag="a"]
-++++++TextView text:"Link with " textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++++Image text:"broken" textSize:16.00 style:4 fgColor:-16776978 bundle:[alt="broken", display="inline", htmlTag="img", src="broken.png"]
-++++++TextView text:" in the middle." textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="http://www.google.com", htmlTag="a"]
-++++++TextView text:"Link with image at the " textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++++Image text:"end, it's a bullet" textSize:16.00 style:4 fgColor:-16776978 bundle:[alt="end, it's a bullet", display="inline", htmlTag="img", src="bullet.png"]
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="http://www.google.com"}]
+++++++Image text:"Link" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="img"}, {display="inline"}, {alt="Link"}, {src="bullet.png"}]
+++++++TextView text:" with image at start." textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="http://www.google.com"}]
+++++++TextView text:"Link with " textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++Image text:"bullet image" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="img"}, {display="inline"}, {alt="bullet image"}, {src="bullet.png"}]
+++++++TextView text:" in the middle." textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="http://www.google.com"}]
+++++++TextView text:"Link with " textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++Image text:"broken" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="img"}, {display="inline"}, {alt="broken"}, {src="broken.png"}]
+++++++TextView text:" in the middle." textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="http://www.google.com"}]
+++++++TextView text:"Link with image at the " textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++Image text:"end, it's a bullet" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="img"}, {display="inline"}, {alt="end, it's a bullet"}, {src="bullet.png"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/abbr-expected-android-assist-data.txt b/content/test/data/accessibility/html/abbr-expected-android-assist-data.txt
index 01d9d6c..263f3d0 100644
--- a/content/test/data/accessibility/html/abbr-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/abbr-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"The " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View text:"World Health Organization" textSize:16.00 style:4 bundle:[display="inline", htmlTag="abbr", title="World Health Organization"]
-++++++TextView text:"WHO" textSize:16.00 style:4 bundle:[display="", htmlTag=""]
-++++TextView text:" was founded in 1948." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"The " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View text:"World Health Organization" textSize:16.0 style:4 htmlInfo:[{htmlTag="abbr"}, {display="inline"}, {title="World Health Organization"}]
+++++++TextView text:"WHO" textSize:16.0 style:4 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" was founded in 1948." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/accordion-expected-android-assist-data.txt b/content/test/data/accessibility/html/accordion-expected-android-assist-data.txt
index f2b27a255..3ea3d800 100644
--- a/content/test/data/accessibility/html/accordion-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/accordion-expected-android-assist-data.txt
@@ -1,23 +1,23 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:18.72 style:1 bundle:[display="block", htmlTag="h3"]
-++++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-controls="section1", aria-expanded="true", display="inline-block", htmlTag="button", id="header1control"]
-++++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"Accordion Section #1" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++View text:"Accordion Section #1" textSize:16.00 style:0 bundle:[aria-labelledby="header1control", display="block", htmlTag="div", id="section1", role="region"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++TextView text:"Content for first section of accordion element." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:18.72 style:1 bundle:[display="block", htmlTag="h3"]
-++++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-controls="section2", aria-expanded="false", display="inline-block", htmlTag="button", id="header2control"]
-++++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"Accordion Section #2" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++View textSize:18.72 style:1 bundle:[display="block", htmlTag="h3"]
-++++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-controls="section3", aria-expanded="false", display="inline-block", htmlTag="button", id="header3control"]
-++++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"Accordion Section #3" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++View textSize:18.72 style:1 bundle:[display="block", htmlTag="h3"]
-++++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-controls="section4", aria-disabled="true", aria-expanded="true", display="inline-block", htmlTag="button", id="header4control"]
-++++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"Accordion Section #4" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++View text:"Accordion Section #4" textSize:16.00 style:0 bundle:[aria-labelledby="header4control", display="block", htmlTag="div", id="section3", role="region"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++TextView text:"Content for forth section of accordion element. This section will always be visible but disabled." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:18.7 style:1 htmlInfo:[{htmlTag="h3"}, {display="block"}]
+++++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}, {aria-controls="section1"}, {aria-expanded="true"}, {id="header1control"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"Accordion Section #1" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"Accordion Section #1" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-labelledby="header1control"}, {id="section1"}, {role="region"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++TextView text:"Content for first section of accordion element." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:18.7 style:1 htmlInfo:[{htmlTag="h3"}, {display="block"}]
+++++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}, {aria-controls="section2"}, {aria-expanded="false"}, {id="header2control"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"Accordion Section #2" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:18.7 style:1 htmlInfo:[{htmlTag="h3"}, {display="block"}]
+++++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}, {aria-controls="section3"}, {aria-expanded="false"}, {id="header3control"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"Accordion Section #3" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:18.7 style:1 htmlInfo:[{htmlTag="h3"}, {display="block"}]
+++++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}, {aria-controls="section4"}, {aria-disabled="true"}, {aria-expanded="true"}, {id="header4control"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"Accordion Section #4" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"Accordion Section #4" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-labelledby="header4control"}, {id="section3"}, {role="region"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++TextView text:"Content for forth section of accordion element. This section will always be visible but disabled." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/action-verbs-expected-android-assist-data.txt b/content/test/data/accessibility/html/action-verbs-expected-android-assist-data.txt
index fe17350f..79e3460 100644
--- a/content/test/data/accessibility/html/action-verbs-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/action-verbs-expected-android-assist-data.txt
@@ -1,53 +1,53 @@
-WebView text:"Action verbs" textSize:16.00 style:0 bundle:[display="", htmlTag="#document", metadata="[<title>Action verbs</title>]"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++TextView text:"Generic div" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:32.00 style:1 bundle:[display="block", htmlTag="h1"]
-++++TextView text:"Heading" textSize:32.00 style:1 bundle:[display="", htmlTag=""]
-++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="button"]
-++++TextView text:"Button" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#", htmlTag="a"]
-++++TextView text:"Link" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++EditText textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", type="text"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++EditText textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", role="searchbox", type="text"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++EditText textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="textarea"]
-++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div"]
-++EditText textSize:16.00 style:0 bundle:[contenteditable="true", display="block", htmlTag="div", role="textbox"]
-++CheckBox textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", type="checkbox"]
-++CheckBox textSize:13.33 style:0 bundle:[checked="", display="inline-block", htmlTag="input", type="checkbox"]
-++RadioButton textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", type="radio"]
-++ToggleButton textSize:16.00 style:0 bundle:[display="block", htmlTag="div", onclick="console.log('hi')", role="switch", tabindex="0"]
-++++TextView text:"ARIA Switch" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="details"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="summary"]
-++++++TextView text:"Summary" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"Pop-up button" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="select"]
-++++View textSize:0.00 style:0 fgColor:0 bundle:[display="", htmlTag=""]
-++++++View text:"Pop-up button" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", onclick="alert('success');"]
-++++TextView text:"Div with click handler" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", onclick="alert('success');", role="group"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++TextView text:"Paragraph with click handler on parent" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="menu"]
-++++MenuItem textSize:16.00 style:0 bundle:[display="block", htmlTag="div", onclick="console.log('hi')", role="menuitem"]
-++++++TextView text:"Menu item 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++MenuItem textSize:16.00 style:0 bundle:[aria-checked="true", display="block", htmlTag="div", onclick="console.log('hi')", role="menuitemcheckbox"]
-++++++TextView text:"Menu item 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++MenuItem textSize:16.00 style:0 bundle:[display="block", htmlTag="div", onclick="console.log('hi')", role="menuitemradio"]
-++++++TextView text:"Menu item 3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++Button textSize:16.00 style:0 bundle:[display="block", htmlTag="div", onclick="console.log('hi')", role="button"]
-++++TextView text:"ARIA Button" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++Button textSize:16.00 style:0 bundle:[display="block", htmlTag="div", onclick="console.log('hi')", role="button", tabindex="1"]
-++++TextView text:"ARIA button with tab index" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++Button textSize:16.00 style:0 bundle:[display="block", htmlTag="div", onclick="console.log('hi')", role="button", tabindex="-1"]
-++++TextView text:"ARIA button with negative tab index" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-activedescendant="active-descendant-button", display="block", htmlTag="div", onclick="console.log('hi')"]
-++++Button textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="active-descendant-button", role="button"]
-++++++TextView text:"ARIA button that is an active descendant" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", onclick="console.log('hi')"]
-++++ToggleButton textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="switch"]
-++++++TextView text:"ARIA switch in clickable container" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++++TextView text:"Generic in clickable container" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView text:"Action verbs" textSize:16.0 style:0 bundle:[metadata="[<title>Action verbs</title>]"] htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++TextView text:"Generic div" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:32.0 style:1 htmlInfo:[{htmlTag="h1"}, {display="block"}]
+++++TextView text:"Heading" textSize:32.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}]
+++++TextView text:"Button" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#"}]
+++++TextView text:"Link" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="text"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {role="searchbox"}, {type="text"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="textarea"}, {display="inline-block"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++EditText textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {contenteditable="true"}, {role="textbox"}]
+++CheckBox textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="checkbox"}]
+++CheckBox textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {checked=""}, {type="checkbox"}]
+++RadioButton textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="radio"}]
+++ToggleButton textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {onclick="console.log('hi')"}, {role="switch"}, {tabindex="0"}]
+++++TextView text:"ARIA Switch" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="details"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="summary"}, {display="list-item"}]
+++++++TextView text:"Summary" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"Pop-up button" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="select"}, {display="inline-block"}]
+++++View textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View text:"Pop-up button" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {onclick="alert('success');"}]
+++++TextView text:"Div with click handler" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {onclick="alert('success');"}, {role="group"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++TextView text:"Paragraph with click handler on parent" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="menu"}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {onclick="console.log('hi')"}, {role="menuitem"}]
+++++++TextView text:"Menu item 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-checked="true"}, {onclick="console.log('hi')"}, {role="menuitemcheckbox"}]
+++++++TextView text:"Menu item 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++MenuItem textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {onclick="console.log('hi')"}, {role="menuitemradio"}]
+++++++TextView text:"Menu item 3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {onclick="console.log('hi')"}, {role="button"}]
+++++TextView text:"ARIA Button" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {onclick="console.log('hi')"}, {role="button"}, {tabindex="1"}]
+++++TextView text:"ARIA button with tab index" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {onclick="console.log('hi')"}, {role="button"}, {tabindex="-1"}]
+++++TextView text:"ARIA button with negative tab index" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-activedescendant="active-descendant-button"}, {onclick="console.log('hi')"}]
+++++Button textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="active-descendant-button"}, {role="button"}]
+++++++TextView text:"ARIA button that is an active descendant" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {onclick="console.log('hi')"}]
+++++ToggleButton textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="switch"}]
+++++++TextView text:"ARIA switch in clickable container" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++++TextView text:"Generic in clickable container" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/actions-expected-android-assist-data.txt b/content/test/data/accessibility/html/actions-expected-android-assist-data.txt
index 1a816369..6b450f2f 100644
--- a/content/test/data/accessibility/html/actions-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/actions-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView text:"Actions" textSize:16.00 style:0 bundle:[display="", htmlTag="#document", metadata="[<title>Actions</title>]"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++SeekBar textSize:13.33 style:0 fgColor:-6449522 bundle:[aria-valuemax="100", aria-valuemin="1", aria-valuenow="50", display="inline-block", htmlTag="input", max="100", min="1", role="slider", step="1", type="range", value="50"]
-++++EditText text:"Test textfield" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", placeholder="Test textfield", type="text"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
\ No newline at end of file
+WebView text:"Actions" textSize:16.0 style:0 bundle:[metadata="[<title>Actions</title>]"] htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++SeekBar textSize:13.3 style:0 fgColor:-6449522 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-valuemax="100"}, {aria-valuemin="1"}, {aria-valuenow="50"}, {max="100"}, {min="1"}, {role="slider"}, {step="1"}, {type="range"}, {value="50"}]
+++++EditText text:"Test textfield" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {placeholder="Test textfield"}, {type="text"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/address-expected-android-assist-data.txt b/content/test/data/accessibility/html/address-expected-android-assist-data.txt
index 35ea917..8b4efef 100644
--- a/content/test/data/accessibility/html/address-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/address-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:2 bundle:[display="block", htmlTag="address"]
-++++TextView text:"Please contact John Citizen for more information." textSize:16.00 style:2 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:2 htmlInfo:[{htmlTag="address"}, {display="block"}]
+++++TextView text:"Please contact John Citizen for more information." textSize:16.0 style:2 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/area-expected-android-assist-data.txt b/content/test/data/accessibility/html/area-expected-android-assist-data.txt
index 8508ab4c..a8d406ec 100644
--- a/content/test/data/accessibility/html/area-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/area-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Image text:"pipe" textSize:16.00 style:0 bundle:[alt="pipe", display="inline", height="126", htmlTag="img", src="pipe.jpg", usemap="#pipe", width="145"]
-++++++View text:"pipe1" textSize:0.00 style:0 fgColor:0 bundle:[alt="pipe1", coords="0,0,145,126", display="inline", href="fake.htm", htmlTag="area", shape="rect"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Image text:"pipe" textSize:16.0 style:0 htmlInfo:[{htmlTag="img"}, {display="inline"}, {alt="pipe"}, {height="126"}, {src="pipe.jpg"}, {usemap="#pipe"}, {width="145"}]
+++++++View text:"pipe1" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="area"}, {display="inline"}, {alt="pipe1"}, {coords="0,0,145,126"}, {href="fake.htm"}, {shape="rect"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/article-expected-android-assist-data.txt b/content/test/data/accessibility/html/article-expected-android-assist-data.txt
index c5527657..0c5ba04 100644
--- a/content/test/data/accessibility/html/article-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/article-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="article"]
-++++TextView text:"This is an article element." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="article"}, {display="block"}]
+++++TextView text:"This is an article element." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/aside-expected-android-assist-data.txt b/content/test/data/accessibility/html/aside-expected-android-assist-data.txt
index 5f1151e..94c8fce 100644
--- a/content/test/data/accessibility/html/aside-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/aside-expected-android-assist-data.txt
@@ -1,16 +1,16 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"The aside tag defines some content aside from the content it is placed in." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="aside"]
-++++View textSize:16.00 style:1 bundle:[display="block", htmlTag="h4"]
-++++++TextView text:"Body aside" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++TextView text:"The aside content should be related to the surrounding content." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="main"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++TextView text:"The main content" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="aside"]
-++++++View textSize:16.00 style:1 bundle:[display="block", htmlTag="h4"]
-++++++++TextView text:"Main aside" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"The aside content should be related to the surrounding content." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"The aside tag defines some content aside from the content it is placed in." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="aside"}, {display="block"}]
+++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="h4"}, {display="block"}]
+++++++TextView text:"Body aside" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++TextView text:"The aside content should be related to the surrounding content." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="main"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++TextView text:"The main content" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="aside"}, {display="block"}]
+++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="h4"}, {display="block"}]
+++++++++TextView text:"Main aside" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"The aside content should be related to the surrounding content." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/aside-inside-other-section-expected-android-assist-data.txt b/content/test/data/accessibility/html/aside-inside-other-section-expected-android-assist-data.txt
index 735b3bdf..d0e1dd6 100644
--- a/content/test/data/accessibility/html/aside-inside-other-section-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/aside-inside-other-section-expected-android-assist-data.txt
@@ -1,15 +1,15 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="article"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="aside"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"Unnamed aside inside article." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View text:"aside" textSize:16.00 style:0 bundle:[display="block", htmlTag="aside", title="aside"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"Named aside inside article." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="section"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="aside"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"Unnamed aside inside section." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View text:"aside" textSize:16.00 style:0 bundle:[display="block", htmlTag="aside", title="aside"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"Named aside inside section." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="article"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="aside"}, {display="block"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"Unnamed aside inside article." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View text:"aside" textSize:16.0 style:0 htmlInfo:[{htmlTag="aside"}, {display="block"}, {title="aside"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"Named aside inside article." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="section"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="aside"}, {display="block"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"Unnamed aside inside section." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View text:"aside" textSize:16.0 style:0 htmlInfo:[{htmlTag="aside"}, {display="block"}, {title="aside"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"Named aside inside section." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/aside-inside-section-role-generic-expected-android-assist-data.txt b/content/test/data/accessibility/html/aside-inside-section-role-generic-expected-android-assist-data.txt
index 939b021..ea7bb4b 100644
--- a/content/test/data/accessibility/html/aside-inside-section-role-generic-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/aside-inside-section-role-generic-expected-android-assist-data.txt
@@ -1,8 +1,8 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="aside"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++TextView text:"aside inside section with role presentational." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="section", role="generic"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="aside"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"aside inside section with role generic." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="aside"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++TextView text:"aside inside section with role presentational." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="section"}, {display="block"}, {role="generic"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="aside"}, {display="block"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"aside inside section with role generic." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/b-expected-android-assist-data.txt b/content/test/data/accessibility/html/b-expected-android-assist-data.txt
index 4fd583c..f57e220f 100644
--- a/content/test/data/accessibility/html/b-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/b-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"Some " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"bold" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++TextView text:" text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"Some " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"bold" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/bdo-expected-android-assist-data.txt b/content/test/data/accessibility/html/bdo-expected-android-assist-data.txt
index def6284..cd29729c 100644
--- a/content/test/data/accessibility/html/bdo-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/bdo-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++TextView text:"Some LTR text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"Some RTL text " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"with some LTR text embedded" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++TextView text:"Some LTR text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"Some RTL text " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"with some LTR text embedded" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/blockquote-expected-android-assist-data.txt b/content/test/data/accessibility/html/blockquote-expected-android-assist-data.txt
index fea533af..e674276 100644
--- a/content/test/data/accessibility/html/blockquote-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/blockquote-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="blockquote"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++TextView text:"First blockquote has a child element." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="blockquote"]
-++++TextView text:"Second blockquote has no child." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="blockquote"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++TextView text:"First blockquote has a child element." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="blockquote"}, {display="block"}]
+++++TextView text:"Second blockquote has no child." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/blockquote-levels-expected-android-assist-data.txt b/content/test/data/accessibility/html/blockquote-levels-expected-android-assist-data.txt
index a4176f8..951032eb 100644
--- a/content/test/data/accessibility/html/blockquote-levels-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/blockquote-levels-expected-android-assist-data.txt
@@ -1,7 +1,7 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="blockquote"]
-++++TextView text:"Top level" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="blockquote"]
-++++++TextView text:"Sub" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="blockquote"]
-++++++++TextView text:"Sub-sub" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="blockquote"}, {display="block"}]
+++++TextView text:"Top level" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="blockquote"}, {display="block"}]
+++++++TextView text:"Sub" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="blockquote"}, {display="block"}]
+++++++++TextView text:"Sub-sub" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/body-expected-android-assist-data.txt b/content/test/data/accessibility/html/body-expected-android-assist-data.txt
index 4679c5d..88e6636 100644
--- a/content/test/data/accessibility/html/body-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/body-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"This test is for body tag" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"This test is for body tag" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/br-expected-android-assist-data.txt b/content/test/data/accessibility/html/br-expected-android-assist-data.txt
index 0043318..15d4708 100644
--- a/content/test/data/accessibility/html/br-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/br-expected-android-assist-data.txt
@@ -1,8 +1,8 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View text:"\n" textSize:16.00 style:0 bundle:[display="", htmlTag="br"]
-++TextView text:"Text line 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"Text line 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View text:"\n" textSize:16.00 style:0 bundle:[display="", htmlTag="br"]
-++++TextView text:"Text line 3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"\n" textSize:16.00 style:0 bundle:[display="", htmlTag="br"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View text:"\n" textSize:16.0 style:0 htmlInfo:[{htmlTag="br"}, {display=""}]
+++TextView text:"Text line 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"Text line 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View text:"\n" textSize:16.0 style:0 htmlInfo:[{htmlTag="br"}, {display=""}]
+++++TextView text:"Text line 3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"\n" textSize:16.0 style:0 htmlInfo:[{htmlTag="br"}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/button-expected-android-assist-data.txt b/content/test/data/accessibility/html/button-expected-android-assist-data.txt
index e225269..9a191afc 100644
--- a/content/test/data/accessibility/html/button-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/button-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="button", onclick="alert('Hello user!')", type="button"]
-++++++TextView text:"Click me!" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}, {onclick="alert('Hello user!')"}, {type="button"}]
+++++++TextView text:"Click me!" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/button-name-calc-expected-android-assist-data.txt b/content/test/data/accessibility/html/button-name-calc-expected-android-assist-data.txt
index 29e9112..8ef74cd 100644
--- a/content/test/data/accessibility/html/button-name-calc-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/button-name-calc-expected-android-assist-data.txt
@@ -1,38 +1,38 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="button", id="c0"]
-++++TextView text:"InnerText0" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="button", id="c1", title="Title1"]
-++++TextView text:"InnerText1" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++Button text:"AriaLabel2 Title2" textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-label="AriaLabel2", display="inline-block", htmlTag="button", id="c2", title="Title2"]
-++++TextView text:"InnerText2" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++Button text:"LabelledBy3 Title3" textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-label="AriaLabel3", aria-labelledby="lb3", display="inline-block", htmlTag="button", id="c3", title="Title3"]
-++++TextView text:"InnerText3" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++Button text:"LabelledBy4 DescribedBy4" textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-describedby="db4", aria-label="AriaLabel4", aria-labelledby="lb4", display="inline-block", htmlTag="button", id="c4", title="Title4"]
-++++TextView text:"InnerText4" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-describedby="db5", display="inline-block", htmlTag="button", id="c5"]
-++++TextView text:"InnerText5" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="button"]
-++++TextView text:"Outer" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div"]
-++++++TextView text:"inner" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="button"]
-++++TextView text:"Outer" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++++View text:"inner1" textSize:13.33 style:0 bundle:[aria-label="inner1", display="block", htmlTag="div"]
-++++++TextView text:"inner2" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="button"]
-++++TextView text:"Outer" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="section"]
-++++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div"]
-++++++++TextView text:"grandchild" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[class="foo @NO_DUMP bar", display="block", htmlTag="p"]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="lb3"]
-++++++TextView text:"LabelledBy3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="lb4"]
-++++++TextView text:"LabelledBy4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="db4"]
-++++++TextView text:"DescribedBy4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="db5"]
-++++++TextView text:"DescribedBy5" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}, {id="c0"}]
+++++TextView text:"InnerText0" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}, {id="c1"}, {title="Title1"}]
+++++TextView text:"InnerText1" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button text:"AriaLabel2 Title2" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}, {aria-label="AriaLabel2"}, {id="c2"}, {title="Title2"}]
+++++TextView text:"InnerText2" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button text:"LabelledBy3 Title3" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}, {aria-label="AriaLabel3"}, {aria-labelledby="lb3"}, {id="c3"}, {title="Title3"}]
+++++TextView text:"InnerText3" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button text:"LabelledBy4 DescribedBy4" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}, {aria-describedby="db4"}, {aria-label="AriaLabel4"}, {aria-labelledby="lb4"}, {id="c4"}, {title="Title4"}]
+++++TextView text:"InnerText4" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}, {aria-describedby="db5"}, {id="c5"}]
+++++TextView text:"InnerText5" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}]
+++++TextView text:"Outer" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++++TextView text:"inner" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}]
+++++TextView text:"Outer" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View text:"inner1" textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="inner1"}]
+++++++TextView text:"inner2" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}]
+++++TextView text:"Outer" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="section"}, {display="block"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++++++TextView text:"grandchild" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {class="foo @NO_DUMP bar"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="lb3"}]
+++++++TextView text:"LabelledBy3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="lb4"}]
+++++++TextView text:"LabelledBy4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="db4"}]
+++++++TextView text:"DescribedBy4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="db5"}]
+++++++TextView text:"DescribedBy5" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/button-with-listbox-popup-expected-android-assist-data.txt b/content/test/data/accessibility/html/button-with-listbox-popup-expected-android-assist-data.txt
index 7dd76b2..478c769 100644
--- a/content/test/data/accessibility/html/button-with-listbox-popup-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/button-with-listbox-popup-expected-android-assist-data.txt
@@ -1,16 +1,16 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="test1"]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="span"]
-++++++TextView text:"Choose one:" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++Button text:"Choose one: Foo" textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-haspopup="listbox", aria-labelledby="span test", display="inline-block", htmlTag="button", id="test"]
-++++++TextView text:"Foo" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++++ListView text:"Choose one:" textSize:16.00 style:0 bundle:[aria-labelledby="span", display="block", htmlTag="ul", id="options", onclick="console.log('hi')", role="listbox", tabindex="-1"]
-++++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", id="option1", role="option"]
-++++++++TextView text:"• " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++TextView text:"Baz" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", id="option2", role="option"]
-++++++++TextView text:"• " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++TextView text:"Bar" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", id="option3", role="option"]
-++++++++TextView text:"• " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++TextView text:"Foo" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="test1"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="span"}]
+++++++TextView text:"Choose one:" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Button text:"Choose one: Foo" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}, {aria-haspopup="listbox"}, {aria-labelledby="span test"}, {id="test"}]
+++++++TextView text:"Foo" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++++ListView text:"Choose one:" textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {aria-labelledby="span"}, {id="options"}, {onclick="console.log('hi')"}, {role="listbox"}, {tabindex="-1"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {id="option1"}, {role="option"}]
+++++++++TextView text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++TextView text:"Baz" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {id="option2"}, {role="option"}]
+++++++++TextView text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++TextView text:"Bar" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {id="option3"}, {role="option"}]
+++++++++TextView text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++TextView text:"Foo" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/canvas-expected-android-assist-data.txt b/content/test/data/accessibility/html/canvas-expected-android-assist-data.txt
index 0e62adaf..4880f59 100644
--- a/content/test/data/accessibility/html/canvas-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/canvas-expected-android-assist-data.txt
@@ -1,7 +1,7 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Image textSize:16.00 style:0 bundle:[display="inline", height="100", htmlTag="canvas", width="100"]
-++++++TextView text:"Static fallback" textSize:0.00 style:0 fgColor:0 bundle:[display="", htmlTag=""]
-++++Image textSize:16.00 style:0 bundle:[display="inline", height="100", htmlTag="canvas", width="100"]
-++++++View textSize:0.00 style:0 fgColor:0 bundle:[display="inline", href="#", htmlTag="a"]
-++++++++TextView text:"Interactive fallback" textSize:0.00 style:0 fgColor:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="canvas"}, {display="inline"}, {height="100"}, {width="100"}]
+++++++TextView text:"Static fallback" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="canvas"}, {display="inline"}, {height="100"}, {width="100"}]
+++++++View textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#"}]
+++++++++TextView text:"Interactive fallback" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/canvas-fallback-expected-android-assist-data.txt b/content/test/data/accessibility/html/canvas-fallback-expected-android-assist-data.txt
index 5d7a6040..124e3aa 100644
--- a/content/test/data/accessibility/html/canvas-fallback-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/canvas-fallback-expected-android-assist-data.txt
@@ -1,15 +1,15 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Image textSize:16.00 style:0 bundle:[display="inline", height="100", htmlTag="canvas", width="100"]
-++++++TextView text:"Static fallback" textSize:0.00 style:0 fgColor:0 bundle:[display="", htmlTag=""]
-++++Image textSize:16.00 style:0 bundle:[display="inline", height="100", htmlTag="canvas", width="100"]
-++++++TextView text:"\n    " textSize:0.00 style:0 fgColor:0 bundle:[display="", htmlTag=""]
-++++++View text:"Aria hidden paragraph in fallback content" textSize:0.00 style:0 fgColor:0 bundle:[aria-describedby="h1", display="block", htmlTag="p", id="p1"]
-++++++++TextView text:"Line breaking content in a fallback" textSize:0.00 style:0 fgColor:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"\n    " textSize:0.00 style:0 fgColor:0 bundle:[display="", htmlTag=""]
-++++++View text:"Visibility hidden paragraph in fallback content" textSize:0.00 style:0 fgColor:0 bundle:[aria-describedby="h2", display="block", htmlTag="p", id="p2"]
-++++++++TextView text:"This is another paragraph in fallback" textSize:0.00 style:0 fgColor:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"\n    " textSize:0.00 style:0 fgColor:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"\n    " textSize:0.00 style:0 fgColor:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"\n    " textSize:0.00 style:0 fgColor:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"\n  " textSize:0.00 style:0 fgColor:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="canvas"}, {display="inline"}, {height="100"}, {width="100"}]
+++++++TextView text:"Static fallback" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="canvas"}, {display="inline"}, {height="100"}, {width="100"}]
+++++++TextView text:"\n    " textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View text:"Aria hidden paragraph in fallback content" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {aria-describedby="h1"}, {id="p1"}]
+++++++++TextView text:"Line breaking content in a fallback" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"\n    " textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View text:"Visibility hidden paragraph in fallback content" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {aria-describedby="h2"}, {id="p2"}]
+++++++++TextView text:"This is another paragraph in fallback" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"\n    " textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"\n    " textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"\n    " textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"\n  " textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/caption-expected-android-assist-data.txt b/content/test/data/accessibility/html/caption-expected-android-assist-data.txt
index 42dab15..1edb7c46 100644
--- a/content/test/data/accessibility/html/caption-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/caption-expected-android-assist-data.txt
@@ -1,27 +1,27 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++GridView text:"Browser and Engine" textSize:16.00 style:0 bundle:[display="table", htmlTag="table"]
-++++View textSize:16.00 style:0 bundle:[display="table-caption", htmlTag="caption"]
-++++++TextView text:"Browser and Engine" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:1 bundle:[display="table-cell", htmlTag="th"]
-++++++++TextView text:"Browser" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:1 bundle:[display="table-cell", htmlTag="th"]
-++++++++TextView text:"Engine" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"Chrome" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"Blink" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"Safari" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"WebKit" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++GridView text:"Name Description" textSize:16.00 style:0 bundle:[aria-label="Name", display="table", htmlTag="table"]
-++++View textSize:16.00 style:0 bundle:[display="table-caption", htmlTag="caption"]
-++++++TextView text:"Description" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"B" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++GridView text:"Browser and Engine" textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="caption"}, {display="table-caption"}]
+++++++TextView text:"Browser and Engine" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}]
+++++++++TextView text:"Browser" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}]
+++++++++TextView text:"Engine" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"Chrome" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"Blink" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"Safari" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"WebKit" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++GridView text:"Name Description" textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}, {aria-label="Name"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="caption"}, {display="table-caption"}]
+++++++TextView text:"Description" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"B" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/character-locations-expected-android-assist-data.txt b/content/test/data/accessibility/html/character-locations-expected-android-assist-data.txt
index 0bc1a9d8..1171c8d 100644
--- a/content/test/data/accessibility/html/character-locations-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/character-locations-expected-android-assist-data.txt
@@ -1,17 +1,17 @@
-WebView text:"Character Locations" textSize:16.00 style:0 bundle:[display="", htmlTag="#document", metadata="[<title>Character Locations</title>]"]
-++View textSize:32.00 style:1 bundle:[display="block", htmlTag="h1"]
-++++TextView text:"Heading" textSize:32.00 style:1 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"Paragraph" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="button"]
-++++TextView text:"Button" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++EditText text:"Input" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", value="Input"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++++TextView text:"Input" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++EditText text:"Textarea" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="textarea"]
-++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div"]
-++++++TextView text:"Textarea" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++Image text:"Image with alt text" textSize:16.00 style:0 bundle:[alt="Image with alt text", display="inline", htmlTag="img"]
-++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#", htmlTag="a"]
-++++Image text:"Image inside link" textSize:16.00 style:4 fgColor:-16776978 bundle:[alt="Image inside link", display="inline", htmlTag="img"]
\ No newline at end of file
+WebView text:"Character Locations" textSize:16.0 style:0 bundle:[metadata="[<title>Character Locations</title>]"] htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:32.0 style:1 htmlInfo:[{htmlTag="h1"}, {display="block"}]
+++++TextView text:"Heading" textSize:32.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"Paragraph" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}]
+++++TextView text:"Button" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++EditText text:"Input" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {value="Input"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++++TextView text:"Input" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++EditText text:"Textarea" textSize:13.3 style:0 htmlInfo:[{htmlTag="textarea"}, {display="inline-block"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++++TextView text:"Textarea" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Image text:"Image with alt text" textSize:16.0 style:0 htmlInfo:[{htmlTag="img"}, {display="inline"}, {alt="Image with alt text"}]
+++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#"}]
+++++Image text:"Image inside link" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="img"}, {display="inline"}, {alt="Image inside link"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/checkbox-name-calc-expected-android-assist-data.txt b/content/test/data/accessibility/html/checkbox-name-calc-expected-android-assist-data.txt
index b396b60..68c16f4 100644
--- a/content/test/data/accessibility/html/checkbox-name-calc-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/checkbox-name-calc-expected-android-assist-data.txt
@@ -1,29 +1,29 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++CheckBox text:"Title0" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", id="c0", title="Title0", type="checkbox"]
-++CheckBox text:"Label1 Title1" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", id="c1", title="Title1", type="checkbox"]
-++CheckBox text:"AriaLabel2 Title2" textSize:13.33 style:0 bundle:[aria-label="AriaLabel2", display="inline-block", htmlTag="input", id="c2", title="Title2", type="checkbox"]
-++CheckBox text:"LabelledBy3 Title3" textSize:13.33 style:0 bundle:[aria-label="AriaLabel3", aria-labelledby="lb3", display="inline-block", htmlTag="input", id="c3", title="Title3", type="checkbox"]
-++CheckBox text:"LabelledBy4 DescribedBy4" textSize:13.33 style:0 bundle:[aria-describedby="db4", aria-label="AriaLabel4", aria-labelledby="lb4", display="inline-block", htmlTag="input", id="c4", title="Title4", type="checkbox"]
-++CheckBox text:"DescribedBy5" textSize:13.33 style:0 bundle:[aria-describedby="db5", display="inline-block", htmlTag="input", id="c5", type="checkbox"]
-++View textSize:16.00 style:0 bundle:[class="@NO_DUMP please", display="block", htmlTag="p"]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", for="c2", htmlTag="label"]
-++++++TextView text:"Label2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", for="c3", htmlTag="label"]
-++++++TextView text:"Label3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", for="c4", htmlTag="label"]
-++++++TextView text:"Label4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="lb3"]
-++++++TextView text:"LabelledBy3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="lb4"]
-++++++TextView text:"LabelledBy4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="db4"]
-++++++TextView text:"DescribedBy4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="db5"]
-++++++TextView text:"DescribedBy5" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++CheckBox text:"Title0" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {id="c0"}, {title="Title0"}, {type="checkbox"}]
+++CheckBox text:"Label1 Title1" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {id="c1"}, {title="Title1"}, {type="checkbox"}]
+++CheckBox text:"AriaLabel2 Title2" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-label="AriaLabel2"}, {id="c2"}, {title="Title2"}, {type="checkbox"}]
+++CheckBox text:"LabelledBy3 Title3" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-label="AriaLabel3"}, {aria-labelledby="lb3"}, {id="c3"}, {title="Title3"}, {type="checkbox"}]
+++CheckBox text:"LabelledBy4 DescribedBy4" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-describedby="db4"}, {aria-label="AriaLabel4"}, {aria-labelledby="lb4"}, {id="c4"}, {title="Title4"}, {type="checkbox"}]
+++CheckBox text:"DescribedBy5" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-describedby="db5"}, {id="c5"}, {type="checkbox"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {class="@NO_DUMP please"}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="label"}, {display="inline"}, {for="c2"}]
+++++++TextView text:"Label2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="label"}, {display="inline"}, {for="c3"}]
+++++++TextView text:"Label3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="label"}, {display="inline"}, {for="c4"}]
+++++++TextView text:"Label4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="lb3"}]
+++++++TextView text:"LabelledBy3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="lb4"}]
+++++++TextView text:"LabelledBy4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="db4"}]
+++++++TextView text:"DescribedBy4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="db5"}]
+++++++TextView text:"DescribedBy5" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/cite-expected-android-assist-data.txt b/content/test/data/accessibility/html/cite-expected-android-assist-data.txt
index 2bd0182..c2ddaaa 100644
--- a/content/test/data/accessibility/html/cite-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/cite-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++Image text:"Pipe" textSize:16.00 style:0 bundle:[alt="Pipe", display="inline", height="277", htmlTag="img", src="pipe.jpg", width="220"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"The pipe" textSize:16.00 style:2 bundle:[display="", htmlTag=""]
-++++TextView text:" clicked by SomeOne." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++Image text:"Pipe" textSize:16.0 style:0 htmlInfo:[{htmlTag="img"}, {display="inline"}, {alt="Pipe"}, {height="277"}, {src="pipe.jpg"}, {width="220"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"The pipe" textSize:16.0 style:2 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" clicked by SomeOne." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/clickable-ancestor-expected-android-assist-data.txt b/content/test/data/accessibility/html/clickable-ancestor-expected-android-assist-data.txt
index e61aafe..edb21142 100644
--- a/content/test/data/accessibility/html/clickable-ancestor-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/clickable-ancestor-expected-android-assist-data.txt
@@ -1,10 +1,10 @@
-WebView text:"Checking nodes marked as clickable" textSize:16.00 style:0 bundle:[display="", htmlTag="#document", metadata="[<title>Checking nodes marked as clickable</title>]"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++TextView text:"Generic div" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:32.00 style:1 bundle:[display="block", htmlTag="h1"]
-++++TextView text:"Heading" textSize:32.00 style:1 bundle:[display="", htmlTag=""]
-++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="button"]
-++++TextView text:"Button" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", onclick="alert('success');", role="group"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++TextView text:"Paragraph with click handler on parent and should be not marked as clickable" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView text:"Checking nodes marked as clickable" textSize:16.0 style:0 bundle:[metadata="[<title>Checking nodes marked as clickable</title>]"] htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++TextView text:"Generic div" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:32.0 style:1 htmlInfo:[{htmlTag="h1"}, {display="block"}]
+++++TextView text:"Heading" textSize:32.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}]
+++++TextView text:"Button" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {onclick="alert('success');"}, {role="group"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++TextView text:"Paragraph with click handler on parent and should be not marked as clickable" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/clickable-score-expected-android-assist-data.txt b/content/test/data/accessibility/html/clickable-score-expected-android-assist-data.txt
index 677e0d3..b524b0c6 100644
--- a/content/test/data/accessibility/html/clickable-score-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/clickable-score-expected-android-assist-data.txt
@@ -1,16 +1,16 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="button", onclick=""]
-++++TextView text:"High score" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++Button textSize:16.00 style:0 bundle:[display="block", htmlTag="div", onclick="", role="button"]
-++++TextView text:"High score" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++Button textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="button"]
-++++TextView text:"No score" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", onclick=""]
-++++TextView text:"Medium score" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="medium score", onclick=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++TextView text:"Low score" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++Button textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="button"]
-++++++TextView text:"High score" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"No score" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}, {onclick=""}]
+++++TextView text:"High score" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {onclick=""}, {role="button"}]
+++++TextView text:"High score" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="button"}]
+++++TextView text:"No score" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {onclick=""}]
+++++TextView text:"Medium score" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="medium score"}, {onclick=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++TextView text:"Low score" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Button textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="button"}]
+++++++TextView text:"High score" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"No score" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/code-expected-android-assist-data.txt b/content/test/data/accessibility/html/code-expected-android-assist-data.txt
index c9c7a76..8427827 100644
--- a/content/test/data/accessibility/html/code-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/code-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++TextView text:"A piece of computer code" textSize:13.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++TextView text:"A piece of computer code" textSize:13.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/col-expected-android-assist-data.txt b/content/test/data/accessibility/html/col-expected-android-assist-data.txt
index 8264919..9b64fdfd 100644
--- a/content/test/data/accessibility/html/col-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/col-expected-android-assist-data.txt
@@ -1,12 +1,12 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++GridView textSize:16.00 style:0 bundle:[display="table", htmlTag="table"]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:1 bundle:[display="table-cell", htmlTag="th"]
-++++++++TextView text:"Browser" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:1 bundle:[display="table-cell", htmlTag="th"]
-++++++++TextView text:"Rendering Engine" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"Chrome" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"Blink" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}]
+++++++++TextView text:"Browser" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}]
+++++++++TextView text:"Rendering Engine" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"Chrome" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"Blink" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/colgroup-expected-android-assist-data.txt b/content/test/data/accessibility/html/colgroup-expected-android-assist-data.txt
index c56a44f2..850ebcd10 100644
--- a/content/test/data/accessibility/html/colgroup-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/colgroup-expected-android-assist-data.txt
@@ -1,12 +1,12 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++GridView textSize:16.00 style:0 bundle:[border="1", display="table", htmlTag="table"]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:1 bundle:[display="table-cell", htmlTag="th"]
-++++++++TextView text:"Single" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:1 bundle:[display="table-cell", htmlTag="th"]
-++++++++TextView text:"Pair" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"A" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"AA" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}, {border="1"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}]
+++++++++TextView text:"Single" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}]
+++++++++TextView text:"Pair" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"A" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"AA" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/combobox-optgroup-expected-android-assist-data.txt b/content/test/data/accessibility/html/combobox-optgroup-expected-android-assist-data.txt
index 28b3e19..e0b9c8b 100644
--- a/content/test/data/accessibility/html/combobox-optgroup-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/combobox-optgroup-expected-android-assist-data.txt
@@ -1,8 +1,8 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++View text:"Mercedes Label" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="select"]
-++++++View textSize:0.00 style:0 fgColor:0 bundle:[display="", htmlTag=""]
-++++++++View text:"Volvo Label" textSize:0.00 style:0 fgColor:0 bundle:[aria-label="Volvo Label", display="block", htmlTag="option", value="volvo"]
-++++++++View text:"Saab Label" textSize:0.00 style:0 fgColor:0 bundle:[aria-label="Saab Label", display="block", htmlTag="option", value="saab"]
-++++++++View text:"Mercedes Label" textSize:0.00 style:0 fgColor:0 bundle:[aria-label="Mercedes Label", display="block", htmlTag="option", selected="", value="mercedes"]
-++++++++View text:"Audi Label" textSize:0.00 style:0 fgColor:0 bundle:[aria-label="Audi Label", display="block", htmlTag="option", value="audi"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++View text:"Mercedes Label" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="select"}, {display="inline-block"}]
+++++++View textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View text:"Volvo Label" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {aria-label="Volvo Label"}, {value="volvo"}]
+++++++++View text:"Saab Label" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {aria-label="Saab Label"}, {value="saab"}]
+++++++++View text:"Mercedes Label" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {aria-label="Mercedes Label"}, {selected=""}, {value="mercedes"}]
+++++++++View text:"Audi Label" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {aria-label="Audi Label"}, {value="audi"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/contenteditable-descendants-expected-android-assist-data.txt b/content/test/data/accessibility/html/contenteditable-descendants-expected-android-assist-data.txt
index eaf177f..14859a8 100644
--- a/content/test/data/accessibility/html/contenteditable-descendants-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/contenteditable-descendants-expected-android-assist-data.txt
@@ -1,24 +1,24 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View text:"A contenteditable with a link and an \n\n and a Button.\nAlways expose editable tables as tables.\n1. Editable list item." textSize:16.00 style:0 bundle:[contenteditable="", display="block", htmlTag="div"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++TextView text:"A contenteditable with a " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#", htmlTag="a"]
-++++++++TextView text:"link" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++++TextView text:" and an " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++Image text:"Image" textSize:16.00 style:0 bundle:[alt="Image", display="inline", htmlTag="img"]
-++++++TextView text:" and a " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++Button text:"Button" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="input", type="button", value="Button"]
-++++++++TextView text:"Button" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++++++TextView text:"." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++GridView textSize:16.00 style:0 bundle:[display="table", htmlTag="table"]
-++++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++++TextView text:"Always expose editable tables as tables." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ol"]
-++++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++++View text:"1. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++++TextView text:"Editable list item." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"Non-editable paragraph." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"Should keep the role but change the state." textSize:16.00 style:0 bundle:[contenteditable="", display="block", htmlTag="p"]
-++++TextView text:"Should keep the role but change the state." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View text:"A contenteditable with a link and an \n\n and a Button.\nAlways expose editable tables as tables.\n1. Editable list item." textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {contenteditable=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++TextView text:"A contenteditable with a " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#"}]
+++++++++TextView text:"link" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:" and an " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++Image text:"Image" textSize:16.0 style:0 htmlInfo:[{htmlTag="img"}, {display="inline"}, {alt="Image"}]
+++++++TextView text:" and a " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++Button text:"Button" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="button"}, {value="Button"}]
+++++++++TextView text:"Button" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++++TextView text:"Always expose editable tables as tables." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ol"}, {display="block"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++++View text:"1. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++++TextView text:"Editable list item." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"Non-editable paragraph." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"Should keep the role but change the state." textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {contenteditable=""}]
+++++TextView text:"Should keep the role but change the state." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/contenteditable-with-embedded-contenteditables-expected-android-assist-data.txt b/content/test/data/accessibility/html/contenteditable-with-embedded-contenteditables-expected-android-assist-data.txt
index a3de9ea..5bfd0f0 100644
--- a/content/test/data/accessibility/html/contenteditable-with-embedded-contenteditables-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/contenteditable-with-embedded-contenteditables-expected-android-assist-data.txt
@@ -1,10 +1,10 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View text:"This is editable.\nThis is not editable.\nBut this one is.\nSo is this one." textSize:16.00 style:0 bundle:[contenteditable="", display="block", htmlTag="div"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++TextView text:"This is editable." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"This is not editable." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View text:"\n" textSize:16.00 style:0 bundle:[display="", htmlTag="br"]
-++++View text:"But this one is." textSize:16.00 style:0 bundle:[contenteditable="true", display="block", htmlTag="p"]
-++++++TextView text:"But this one is." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View text:"So is this one." textSize:16.00 style:0 bundle:[contenteditable="true", display="block", htmlTag="p"]
-++++++TextView text:"So is this one." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View text:"This is editable.\nThis is not editable.\nBut this one is.\nSo is this one." textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {contenteditable=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++TextView text:"This is editable." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"This is not editable." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View text:"\n" textSize:16.0 style:0 htmlInfo:[{htmlTag="br"}, {display=""}]
+++++View text:"But this one is." textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {contenteditable="true"}]
+++++++TextView text:"But this one is." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View text:"So is this one." textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {contenteditable="true"}]
+++++++TextView text:"So is this one." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/contenteditable-with-no-descendants-expected-android-assist-data.txt b/content/test/data/accessibility/html/contenteditable-with-no-descendants-expected-android-assist-data.txt
index 7f63d38e..c2be0320 100644
--- a/content/test/data/accessibility/html/contenteditable-with-no-descendants-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/contenteditable-with-no-descendants-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View text:"label" textSize:16.00 style:0 bundle:[aria-label="label", contenteditable="", display="block", htmlTag="div"]
-++View text:"description" textSize:16.00 style:0 bundle:[aria-describedby="description", contenteditable="", display="block", htmlTag="div"]
-++View text:"title" textSize:16.00 style:0 bundle:[contenteditable="", display="block", htmlTag="div", title="title"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p", id="description"]
-++++TextView text:"description" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View text:"label" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="label"}, {contenteditable=""}]
+++View text:"description" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-describedby="description"}, {contenteditable=""}]
+++View text:"title" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {contenteditable=""}, {title="title"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {id="description"}]
+++++TextView text:"description" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/continuations-expected-android-assist-data.txt b/content/test/data/accessibility/html/continuations-expected-android-assist-data.txt
index f25d914..47428f59 100644
--- a/content/test/data/accessibility/html/continuations-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/continuations-expected-android-assist-data.txt
@@ -1,36 +1,36 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View text:"Group 1" textSize:16.00 style:0 bundle:[aria-label="Group 1", display="block", htmlTag="div", role="group"]
-++++View textSize:16.00 style:3 bundle:[display="block", htmlTag="div"]
-++++++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="button", id="before"]
-++++++++TextView text:"Before" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:1 bundle:[display="block", htmlTag="div", id="after"]
-++++++TextView text:"After" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++View text:"Group 2" textSize:16.00 style:0 bundle:[aria-label="Group 2", display="block", htmlTag="div", role="group"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="before"]
-++++++TextView text:"Before" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="after"]
-++++++TextView text:"After" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"Group 3" textSize:16.00 style:0 bundle:[aria-label="Group 3", display="block", htmlTag="div", role="group"]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="a", name="a"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="before"]
-++++++++TextView text:"Before" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="ever"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="a", name="a"]
-++++++++TextView text:"Ever " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#", htmlTag="a", id="after"]
-++++++++TextView text:"After" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++View text:"Group 4" textSize:16.00 style:0 bundle:[aria-label="Group 4", display="block", htmlTag="div", role="group"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="before"]
-++++++TextView text:"Before" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p", id="after"]
-++++++++TextView text:"After" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"Group 5" textSize:16.00 style:0 bundle:[aria-label="Group 5", display="block", htmlTag="div", role="group"]
-++++TextView text:"Italic only " textSize:16.00 style:2 bundle:[display="", htmlTag=""]
-++++TextView text:"italic and bold" textSize:16.00 style:3 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:3 bundle:[display="block", htmlTag="div"]
-++++++TextView text:"Wow, a block!" textSize:16.00 style:3 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:3 bundle:[display="block", htmlTag="div"]
-++++++TextView text:"Wow, another block!" textSize:16.00 style:3 bundle:[display="", htmlTag=""]
-++++TextView text:"More italic and bold text" textSize:16.00 style:3 bundle:[display="", htmlTag=""]
-++++TextView text:" More italic text" textSize:16.00 style:2 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View text:"Group 1" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Group 1"}, {role="group"}]
+++++View textSize:16.0 style:3 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}, {id="before"}]
+++++++++TextView text:"Before" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="after"}]
+++++++TextView text:"After" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"Group 2" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Group 2"}, {role="group"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="before"}]
+++++++TextView text:"Before" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="after"}]
+++++++TextView text:"After" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"Group 3" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Group 3"}, {role="group"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="a"}, {display="inline"}, {name="a"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="before"}]
+++++++++TextView text:"Before" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="ever"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="a"}, {display="inline"}, {name="a"}]
+++++++++TextView text:"Ever " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#"}, {id="after"}]
+++++++++TextView text:"After" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"Group 4" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Group 4"}, {role="group"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="before"}]
+++++++TextView text:"Before" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {id="after"}]
+++++++++TextView text:"After" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"Group 5" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="Group 5"}, {role="group"}]
+++++TextView text:"Italic only " textSize:16.0 style:2 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"italic and bold" textSize:16.0 style:3 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:3 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++++TextView text:"Wow, a block!" textSize:16.0 style:3 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:3 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++++TextView text:"Wow, another block!" textSize:16.0 style:3 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"More italic and bold text" textSize:16.0 style:3 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" More italic text" textSize:16.0 style:2 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/dd-expected-android-assist-data.txt b/content/test/data/accessibility/html/dd-expected-android-assist-data.txt
index 033dbd25..7bf3488c 100644
--- a/content/test/data/accessibility/html/dd-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/dd-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="dl"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="dt"]
-++++++TextView text:"Coffee" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="dd"]
-++++++TextView text:"Black hot drink" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="dl"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="dt"}, {display="block"}]
+++++++TextView text:"Coffee" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="dd"}, {display="block"}]
+++++++TextView text:"Black hot drink" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/del-expected-android-assist-data.txt b/content/test/data/accessibility/html/del-expected-android-assist-data.txt
index dde3084..45a6d9a 100644
--- a/content/test/data/accessibility/html/del-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/del-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"I am " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:8 bundle:[display="inline", htmlTag="del"]
-++++++TextView text:"vegetarian" textSize:16.00 style:8 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"I am " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:8 htmlInfo:[{htmlTag="del"}, {display="inline"}]
+++++++TextView text:"vegetarian" textSize:16.0 style:8 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/details-expected-android-assist-data.txt b/content/test/data/accessibility/html/details-expected-android-assist-data.txt
index 674c1d9..31320a8 100644
--- a/content/test/data/accessibility/html/details-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/details-expected-android-assist-data.txt
@@ -1,9 +1,9 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="details"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="summary"]
-++++++TextView text:"details tag" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="details", open=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="summary"]
-++++++TextView text:"details tag open" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++TextView text:"The details tag with open specifies that the details should be visible (open) to the user." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="details"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="summary"}, {display="list-item"}]
+++++++TextView text:"details tag" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="details"}, {display="block"}, {open=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="summary"}, {display="list-item"}]
+++++++TextView text:"details tag open" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++TextView text:"The details tag with open specifies that the details should be visible (open) to the user." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/details-name-expected-android-assist-data.txt b/content/test/data/accessibility/html/details-name-expected-android-assist-data.txt
index 314a2ed8..85e582e 100644
--- a/content/test/data/accessibility/html/details-name-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/details-name-expected-android-assist-data.txt
@@ -1,16 +1,16 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="details"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="summary"]
-++++++TextView text:"the summary" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="section"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="details", name="properties", open=""]
-++++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="summary"]
-++++++++TextView text:"materials" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"Info about what it's made of." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="details", name="properties"]
-++++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="summary"]
-++++++++TextView text:"dimensions" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="details", name="properties"]
-++++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="summary"]
-++++++++TextView text:"origin" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="details"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="summary"}, {display="list-item"}]
+++++++TextView text:"the summary" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="section"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="details"}, {display="block"}, {name="properties"}, {open=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="summary"}, {display="list-item"}]
+++++++++TextView text:"materials" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"Info about what it's made of." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="details"}, {display="block"}, {name="properties"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="summary"}, {display="list-item"}]
+++++++++TextView text:"dimensions" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="details"}, {display="block"}, {name="properties"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="summary"}, {display="list-item"}]
+++++++++TextView text:"origin" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/dfn-expected-android-assist-data.txt b/content/test/data/accessibility/html/dfn-expected-android-assist-data.txt
index 761b5fa7..2751d4f 100644
--- a/content/test/data/accessibility/html/dfn-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/dfn-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++View textSize:16.00 style:2 bundle:[display="inline", htmlTag="dfn"]
-++++++TextView text:"Web Browser" textSize:16.00 style:2 bundle:[display="", htmlTag=""]
-++++TextView text:" A computer program with a graphical user interface for displaying HTML files, used to navigate the World Wide Web." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++View textSize:16.0 style:2 htmlInfo:[{htmlTag="dfn"}, {display="inline"}]
+++++++TextView text:"Web Browser" textSize:16.0 style:2 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" A computer program with a graphical user interface for displaying HTML files, used to navigate the World Wide Web." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/dialog-expected-android-assist-data.txt b/content/test/data/accessibility/html/dialog-expected-android-assist-data.txt
index d082f00..9dd4e18 100644
--- a/content/test/data/accessibility/html/dialog-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/dialog-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++Dialog textSize:16.00 style:0 bundle:[display="block", htmlTag="dialog", open=""]
-++++TextView text:"Text in dialog" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++Dialog textSize:16.0 style:0 htmlInfo:[{htmlTag="dialog"}, {display="block"}, {open=""}]
+++++TextView text:"Text in dialog" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/disabled-expected-android-assist-data.txt b/content/test/data/accessibility/html/disabled-expected-android-assist-data.txt
index 8375afe..25d1aca8 100644
--- a/content/test/data/accessibility/html/disabled-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/disabled-expected-android-assist-data.txt
@@ -1,17 +1,17 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++CheckBox text:"Enabled" textSize:13.33 style:0 bundle:[aria-label="Enabled", display="inline-block", htmlTag="input", type="checkbox"]
-++CheckBox text:"Disabled" textSize:13.33 style:0 fgColor:-11250604 bundle:[aria-label="Disabled", disabled="", display="inline-block", htmlTag="input", type="checkbox"]
-++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="button"]
-++++TextView text:"Enabled" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++Button textSize:13.33 style:0 fgColor:1292898320 bgColor:1307570159 bundle:[disabled="", display="inline-block", htmlTag="button"]
-++++TextView text:"Disabled" textSize:13.33 style:0 fgColor:1292898320 bgColor:1307570159 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="form"]
-++++TextView text:"Enabled form " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++CheckBox text:"Checkbox" textSize:13.33 style:0 bundle:[aria-label="Checkbox", display="inline-block", htmlTag="input", type="checkbox"]
-++++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="button"]
-++++++TextView text:"Button" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-disabled="true", display="block", htmlTag="form"]
-++++TextView text:"Disabled form " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++CheckBox text:"Checkbox" textSize:13.33 style:0 bundle:[aria-label="Checkbox", display="inline-block", htmlTag="input", type="checkbox"]
-++++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="button"]
-++++++TextView text:"Button" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++CheckBox text:"Enabled" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-label="Enabled"}, {type="checkbox"}]
+++CheckBox text:"Disabled" textSize:13.3 style:0 fgColor:-11250604 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-label="Disabled"}, {disabled=""}, {type="checkbox"}]
+++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}]
+++++TextView text:"Enabled" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:13.3 style:0 fgColor:1292898320 bgColor:1307570159 htmlInfo:[{htmlTag="button"}, {display="inline-block"}, {disabled=""}]
+++++TextView text:"Disabled" textSize:13.3 style:0 fgColor:1292898320 bgColor:1307570159 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="form"}, {display="block"}]
+++++TextView text:"Enabled form " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++CheckBox text:"Checkbox" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-label="Checkbox"}, {type="checkbox"}]
+++++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}]
+++++++TextView text:"Button" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="form"}, {display="block"}, {aria-disabled="true"}]
+++++TextView text:"Disabled form " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++CheckBox text:"Checkbox" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-label="Checkbox"}, {type="checkbox"}]
+++++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}]
+++++++TextView text:"Button" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/div-expected-android-assist-data.txt b/content/test/data/accessibility/html/div-expected-android-assist-data.txt
index c446bcb..566f8ebeb 100644
--- a/content/test/data/accessibility/html/div-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/div-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++TextView text:"Unfocusable div" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", tabindex="0"]
-++++TextView text:"Focusable div" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++TextView text:"Unfocusable div" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {tabindex="0"}]
+++++TextView text:"Focusable div" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/dl-expected-android-assist-data.txt b/content/test/data/accessibility/html/dl-expected-android-assist-data.txt
index 01a0e1d..7afd1f41 100644
--- a/content/test/data/accessibility/html/dl-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/dl-expected-android-assist-data.txt
@@ -1,8 +1,8 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="dl"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="dt"]
-++++++TextView text:"Term" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="dd"]
-++++++TextView text:"Description" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="definition"]
-++++TextView text:"Definition" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="dl"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="dt"}, {display="block"}]
+++++++TextView text:"Term" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="dd"}, {display="block"}]
+++++++TextView text:"Description" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="definition"}]
+++++TextView text:"Definition" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/dt-expected-android-assist-data.txt b/content/test/data/accessibility/html/dt-expected-android-assist-data.txt
index 033dbd25..7bf3488c 100644
--- a/content/test/data/accessibility/html/dt-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/dt-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="dl"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="dt"]
-++++++TextView text:"Coffee" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="dd"]
-++++++TextView text:"Black hot drink" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="dl"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="dt"}, {display="block"}]
+++++++TextView text:"Coffee" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="dd"}, {display="block"}]
+++++++TextView text:"Black hot drink" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/element-class-id-src-attr-expected-android-assist-data.txt b/content/test/data/accessibility/html/element-class-id-src-attr-expected-android-assist-data.txt
index 540e431..9088224 100644
--- a/content/test/data/accessibility/html/element-class-id-src-attr-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/element-class-id-src-attr-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:32.00 style:1 bundle:[class="headerClass", display="block", htmlTag="h1", id="headerID"]
-++++TextView text:"Image" textSize:32.00 style:1 bundle:[display="", htmlTag=""]
-++Image text:"ImageAlt" textSize:16.00 style:0 bundle:[alt="ImageAlt", class="imageClass", display="inline", height="100", htmlTag="img", id="imageID", src="greenbox.png", width="200"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:32.0 style:1 htmlInfo:[{htmlTag="h1"}, {display="block"}, {id="headerID"}, {class="headerClass"}]
+++++TextView text:"Image" textSize:32.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++Image text:"ImageAlt" textSize:16.0 style:0 htmlInfo:[{htmlTag="img"}, {display="inline"}, {alt="ImageAlt"}, {height="100"}, {id="imageID"}, {src="greenbox.png"}, {width="200"}, {class="imageClass"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/em-expected-android-assist-data.txt b/content/test/data/accessibility/html/em-expected-android-assist-data.txt
index b25c974e..1a4d348e 100644
--- a/content/test/data/accessibility/html/em-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/em-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++TextView text:"One word is " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"emphasized" textSize:16.00 style:2 bundle:[display="", htmlTag=""]
-++++TextView text:"." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++TextView text:"One word is " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"emphasized" textSize:16.0 style:2 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/embed-expected-android-assist-data.txt b/content/test/data/accessibility/html/embed-expected-android-assist-data.txt
index 958e239..18370338 100644
--- a/content/test/data/accessibility/html/embed-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/embed-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="embed", src="../../../../media/test/data/bear.swf"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="embed"}, {display="inline"}, {src="../../../../media/test/data/bear.swf"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/fieldset-expected-android-assist-data.txt b/content/test/data/accessibility/html/fieldset-expected-android-assist-data.txt
index 14540301..0cbc795 100644
--- a/content/test/data/accessibility/html/fieldset-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/fieldset-expected-android-assist-data.txt
@@ -1,9 +1,9 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="form"]
-++++View text:"Browser Engines:" textSize:16.00 style:0 bundle:[display="block", htmlTag="fieldset"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="legend"]
-++++++++TextView text:"Browser Engines:" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"Which cake do you prefer?" textSize:16.00 style:0 bundle:[display="block", htmlTag="fieldset"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="legend"]
-++++++View textSize:24.00 style:1 bundle:[display="block", htmlTag="h2"]
-++++++++TextView text:"Which cake do you prefer?" textSize:24.00 style:1 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="form"}, {display="block"}]
+++++View text:"Browser Engines:" textSize:16.0 style:0 htmlInfo:[{htmlTag="fieldset"}, {display="block"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="legend"}, {display="block"}]
+++++++++TextView text:"Browser Engines:" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"Which cake do you prefer?" textSize:16.0 style:0 htmlInfo:[{htmlTag="fieldset"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="legend"}, {display="block"}]
+++++++View textSize:24.0 style:1 htmlInfo:[{htmlTag="h2"}, {display="block"}]
+++++++++TextView text:"Which cake do you prefer?" textSize:24.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/figcaption-expected-android-assist-data.txt b/content/test/data/accessibility/html/figcaption-expected-android-assist-data.txt
index 80145561..74054591 100644
--- a/content/test/data/accessibility/html/figcaption-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/figcaption-expected-android-assist-data.txt
@@ -1,9 +1,9 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="figure"]
-++++Image text:"This is a green box." textSize:16.00 style:0 bundle:[alt="This is a green box.", display="inline", htmlTag="img", src="greenbox.png"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="figcaption"]
-++++++TextView text:"Fig.1 - A green Box" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[aria-details="", display="block", htmlTag="figure"]
-++++Image text:"This is a blue box." textSize:16.00 style:0 bundle:[alt="This is a blue box.", display="inline", htmlTag="img", src="greenbox.png"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="figcaption"]
-++++++TextView text:"Fig.2 - A blue Box" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="figure"}, {display="block"}]
+++++Image text:"This is a green box." textSize:16.0 style:0 htmlInfo:[{htmlTag="img"}, {display="inline"}, {alt="This is a green box."}, {src="greenbox.png"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="figcaption"}, {display="block"}]
+++++++TextView text:"Fig.1 - A green Box" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="figure"}, {display="block"}, {aria-details=""}]
+++++Image text:"This is a blue box." textSize:16.0 style:0 htmlInfo:[{htmlTag="img"}, {display="inline"}, {alt="This is a blue box."}, {src="greenbox.png"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="figcaption"}, {display="block"}]
+++++++TextView text:"Fig.2 - A blue Box" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/figure-expected-android-assist-data.txt b/content/test/data/accessibility/html/figure-expected-android-assist-data.txt
index c8a742c..749a368 100644
--- a/content/test/data/accessibility/html/figure-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/figure-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="figure"]
-++++Image text:"Sunspots" textSize:16.00 style:0 bundle:[alt="Sunspots", display="inline", height="228", htmlTag="img", src="pipe.jpg", width="304"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="figure"}, {display="block"}]
+++++Image text:"Sunspots" textSize:16.0 style:0 htmlInfo:[{htmlTag="img"}, {display="inline"}, {alt="Sunspots"}, {height="228"}, {src="pipe.jpg"}, {width="304"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/fixed-width-text-expected-android-assist-data.txt b/content/test/data/accessibility/html/fixed-width-text-expected-android-assist-data.txt
index cc8648ae..dbe1ebc 100644
--- a/content/test/data/accessibility/html/fixed-width-text-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/fixed-width-text-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:17.89 style:0 bundle:[class="fixed-width", display="block", htmlTag="p"]
-++++TextView text:"Hello," textSize:17.89 style:0 bundle:[display="", htmlTag=""]
-++++View text:"\n" textSize:17.89 style:0 bundle:[display="", htmlTag="br"]
-++++TextView text:"World" textSize:17.89 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:17.9 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {class="fixed-width"}]
+++++TextView text:"Hello," textSize:17.9 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View text:"\n" textSize:17.9 style:0 htmlInfo:[{htmlTag="br"}, {display=""}]
+++++TextView text:"World" textSize:17.9 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/footer-expected-android-assist-data.txt b/content/test/data/accessibility/html/footer-expected-android-assist-data.txt
index acfcc66..95a6e9d 100644
--- a/content/test/data/accessibility/html/footer-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/footer-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="footer"]
-++++TextView text:"Footer element" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="footer"}, {display="block"}]
+++++TextView text:"Footer element" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/footer-inside-other-section-expected-android-assist-data.txt b/content/test/data/accessibility/html/footer-inside-other-section-expected-android-assist-data.txt
index 93814a5..c6e2e88 100644
--- a/content/test/data/accessibility/html/footer-inside-other-section-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/footer-inside-other-section-expected-android-assist-data.txt
@@ -1,13 +1,13 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="article"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="footer"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"footer inside article." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="section"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="footer"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"footer inside section." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="main"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="footer"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"footer inside main." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="article"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="footer"}, {display="block"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"footer inside article." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="section"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="footer"}, {display="block"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"footer inside section." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="main"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="footer"}, {display="block"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"footer inside main." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/form-expected-android-assist-data.txt b/content/test/data/accessibility/html/form-expected-android-assist-data.txt
index 3289f7fa..c63304d 100644
--- a/content/test/data/accessibility/html/form-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/form-expected-android-assist-data.txt
@@ -1,7 +1,7 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[action="POST", display="block", htmlTag="form"]
-++++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="input", type="submit"]
-++++++TextView text:"Submit" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++View text:"Name" textSize:16.00 style:0 bundle:[action="POST", aria-label="Name", display="block", htmlTag="form"]
-++++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="input", type="submit"]
-++++++TextView text:"Submit" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="form"}, {display="block"}, {action="POST"}]
+++++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="submit"}]
+++++++TextView text:"Submit" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"Name" textSize:16.0 style:0 htmlInfo:[{htmlTag="form"}, {display="block"}, {action="POST"}, {aria-label="Name"}]
+++++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="submit"}]
+++++++TextView text:"Submit" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/header-expected-android-assist-data.txt b/content/test/data/accessibility/html/header-expected-android-assist-data.txt
index 65330e1..43e7504 100644
--- a/content/test/data/accessibility/html/header-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/header-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="header"]
-++++TextView text:"Chromium Browser" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="header"}, {display="block"}]
+++++TextView text:"Chromium Browser" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/header-inside-other-section-expected-android-assist-data.txt b/content/test/data/accessibility/html/header-inside-other-section-expected-android-assist-data.txt
index 3ecbcfff..ff6f956f 100644
--- a/content/test/data/accessibility/html/header-inside-other-section-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/header-inside-other-section-expected-android-assist-data.txt
@@ -1,13 +1,13 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="article"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="header"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"Header inside article." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="section"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="header"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"Header inside section." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="main"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="header"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"Header inside main." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="article"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="header"}, {display="block"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"Header inside article." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="section"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="header"}, {display="block"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"Header inside section." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="main"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="header"}, {display="block"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"Header inside main." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/heading-expected-android-assist-data.txt b/content/test/data/accessibility/html/heading-expected-android-assist-data.txt
index 6de6cfe5..314b4be 100644
--- a/content/test/data/accessibility/html/heading-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/heading-expected-android-assist-data.txt
@@ -1,13 +1,13 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:32.00 style:1 bundle:[display="block", htmlTag="h1"]
-++++TextView text:"Heading 1" textSize:32.00 style:1 bundle:[display="", htmlTag=""]
-++View textSize:24.00 style:1 bundle:[display="block", htmlTag="h2"]
-++++TextView text:"Heading 2" textSize:24.00 style:1 bundle:[display="", htmlTag=""]
-++View textSize:18.72 style:1 bundle:[display="block", htmlTag="h3"]
-++++TextView text:"Heading 3" textSize:18.72 style:1 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:1 bundle:[display="block", htmlTag="h4"]
-++++TextView text:"Heading 4" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++View textSize:13.28 style:1 bundle:[display="block", htmlTag="h5"]
-++++TextView text:"Heading 5" textSize:13.28 style:1 bundle:[display="", htmlTag=""]
-++View textSize:10.72 style:1 bundle:[display="block", htmlTag="h6"]
-++++TextView text:"Heading 6" textSize:10.72 style:1 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:32.0 style:1 htmlInfo:[{htmlTag="h1"}, {display="block"}]
+++++TextView text:"Heading 1" textSize:32.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:24.0 style:1 htmlInfo:[{htmlTag="h2"}, {display="block"}]
+++++TextView text:"Heading 2" textSize:24.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:18.7 style:1 htmlInfo:[{htmlTag="h3"}, {display="block"}]
+++++TextView text:"Heading 3" textSize:18.7 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:1 htmlInfo:[{htmlTag="h4"}, {display="block"}]
+++++TextView text:"Heading 4" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:13.3 style:1 htmlInfo:[{htmlTag="h5"}, {display="block"}]
+++++TextView text:"Heading 5" textSize:13.3 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:10.7 style:1 htmlInfo:[{htmlTag="h6"}, {display="block"}]
+++++TextView text:"Heading 6" textSize:10.7 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/heading-with-tabIndex-expected-android-assist-data.txt b/content/test/data/accessibility/html/heading-with-tabIndex-expected-android-assist-data.txt
index b866a69..2e5846d7 100644
--- a/content/test/data/accessibility/html/heading-with-tabIndex-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/heading-with-tabIndex-expected-android-assist-data.txt
@@ -1,9 +1,9 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:24.00 style:1 bundle:[display="block", htmlTag="h2"]
-++++TextView text:"Heading 2, no tabIndex" textSize:24.00 style:1 bundle:[display="", htmlTag=""]
-++View textSize:32.00 style:1 bundle:[display="block", htmlTag="h1", tabindex="-1"]
-++++TextView text:"Heading 1, tabIndex of negative 1" textSize:32.00 style:1 bundle:[display="", htmlTag=""]
-++View textSize:18.72 style:1 bundle:[display="block", htmlTag="h3", tabindex="0"]
-++++TextView text:"Heading 3, tabIndex of 0" textSize:18.72 style:1 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:1 bundle:[display="block", htmlTag="h4", tabindex="1"]
-++++TextView text:"Heading 4, tabIndex of 1" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:24.0 style:1 htmlInfo:[{htmlTag="h2"}, {display="block"}]
+++++TextView text:"Heading 2, no tabIndex" textSize:24.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:32.0 style:1 htmlInfo:[{htmlTag="h1"}, {display="block"}, {tabindex="-1"}]
+++++TextView text:"Heading 1, tabIndex of negative 1" textSize:32.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:18.7 style:1 htmlInfo:[{htmlTag="h3"}, {display="block"}, {tabindex="0"}]
+++++TextView text:"Heading 3, tabIndex of 0" textSize:18.7 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:1 htmlInfo:[{htmlTag="h4"}, {display="block"}, {tabindex="1"}]
+++++TextView text:"Heading 4, tabIndex of 1" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/hr-expected-android-assist-data.txt b/content/test/data/accessibility/html/hr-expected-android-assist-data.txt
index 78cce22a..f7c7c92b 100644
--- a/content/test/data/accessibility/html/hr-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/hr-expected-android-assist-data.txt
@@ -1,9 +1,9 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"Before." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"Dividing line" textSize:16.00 style:0 bundle:[aria-label="Dividing line", display="block", htmlTag="hr"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"Middle." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="hr"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"After." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"Before." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"Dividing line" textSize:16.0 style:0 htmlInfo:[{htmlTag="hr"}, {display="block"}, {aria-label="Dividing line"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"Middle." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="hr"}, {display="block"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"After." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/html-attributes-and-tag-names-expected-android-assist-data.txt b/content/test/data/accessibility/html/html-attributes-and-tag-names-expected-android-assist-data.txt
index d7ed73f..14098b5a 100644
--- a/content/test/data/accessibility/html/html-attributes-and-tag-names-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/html-attributes-and-tag-names-expected-android-assist-data.txt
@@ -1,12 +1,12 @@
-WebView text:"Hello World" textSize:16.00 style:0 bundle:[display="", htmlTag="#document", metadata="[<title>Hello World</title>, <meta charset="utf-8"></meta>, <link ref="canonical" href="https://abc.com"></link>, <script type="application/ld+json">{}</script>]"]
-++View textSize:32.00 style:1 bundle:[display="block", htmlTag="h1"]
-++++TextView text:"Heading" textSize:32.00 style:1 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"Paragraph" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++EditText textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++Button text:"c" textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-label="c", class="b", display="inline-block", htmlTag="button", id="a"]
-++++TextView text:"D" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="button"]
-++++TextView text:"Click" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView text:"Hello World" textSize:16.0 style:0 bundle:[metadata="[<title>Hello World</title>, <meta charset="utf-8"></meta>, <link ref="canonical" href="https://abc.com"></link>, <script type="application/ld+json">{}</script>]"] htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:32.0 style:1 htmlInfo:[{htmlTag="h1"}, {display="block"}]
+++++TextView text:"Heading" textSize:32.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"Paragraph" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++Button text:"c" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}, {aria-label="c"}, {id="a"}, {class="b"}]
+++++TextView text:"D" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}]
+++++TextView text:"Click" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/html-expected-android-assist-data.txt b/content/test/data/accessibility/html/html-expected-android-assist-data.txt
index 2b8f63b..1d745c9 100644
--- a/content/test/data/accessibility/html/html-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/html-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView text:"HTML element" textSize:16.00 style:0 bundle:[display="", htmlTag="#document", metadata="[<title>Even the HTML element is part of the page.</title>]"]
-++View text:"BODY element" textSize:16.00 style:0 bundle:[aria-label="BODY element", display="block", htmlTag="body"]
-++++Button text:"Button element" textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-label="Button element", display="inline-block", htmlTag="button"]
-++++++TextView text:"Button" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView text:"HTML element" textSize:16.0 style:0 bundle:[metadata="[<title>Even the HTML element is part of the page.</title>]"] htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View text:"BODY element" textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}, {aria-label="BODY element"}]
+++++Button text:"Button element" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}, {aria-label="Button element"}]
+++++++TextView text:"Button" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/i-expected-android-assist-data.txt b/content/test/data/accessibility/html/i-expected-android-assist-data.txt
index 56d2acd..276fcf7 100644
--- a/content/test/data/accessibility/html/i-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/i-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"This is to check " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"italic property" textSize:16.00 style:2 bundle:[display="", htmlTag=""]
-++++TextView text:" using i tag." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"This is to check " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"italic property" textSize:16.0 style:2 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" using i tag." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/id-expected-android-assist-data.txt b/content/test/data/accessibility/html/id-expected-android-assist-data.txt
index 0f28a79..4f9fd56 100644
--- a/content/test/data/accessibility/html/id-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/id-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"No id" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p", id="para2"]
-++++TextView text:"Has id" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"No id" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {id="para2"}]
+++++TextView text:"Has id" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/iframe-cross-process-expected-android-assist-data.txt b/content/test/data/accessibility/html/iframe-cross-process-expected-android-assist-data.txt
index ad09883..ac22c11 100644
--- a/content/test/data/accessibility/html/iframe-cross-process-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/iframe-cross-process-expected-android-assist-data.txt
@@ -1,12 +1,12 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"Before frame" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++View textSize:16.00 style:0 bundle:[aria-label="Cross-process iframe", display="inline", htmlTag="iframe", src="/cross-site/1.com/accessibility/html/frame/static_text.html"]
-++++++View text:"Error" textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++++++++TextView text:"Could not load the requested resource." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++++View text:"\n" textSize:16.00 style:0 bundle:[display="", htmlTag="br"]
-++++++++++TextView text:"Error code: -6 (net::ERR_FILE_NOT_FOUND)" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"After frame" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"Before frame" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="iframe"}, {display="inline"}, {aria-label="Cross-process iframe"}, {src="/cross-site/1.com/accessibility/html/frame/static_text.html"}]
+++++++View text:"Error" textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++++++++TextView text:"Could not load the requested resource." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++++View text:"\n" textSize:16.0 style:0 htmlInfo:[{htmlTag="br"}, {display=""}]
+++++++++++TextView text:"Error code: -6 (net::ERR_FILE_NOT_FOUND)" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"After frame" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/iframe-expected-android-assist-data.txt b/content/test/data/accessibility/html/iframe-expected-android-assist-data.txt
index d0c9e509..69767d5 100644
--- a/content/test/data/accessibility/html/iframe-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/iframe-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++View textSize:16.00 style:0 bundle:[aria-label="Empty iframe", display="inline", htmlTag="iframe", src="frame/empty.html", style="width:100px; height: 100px;"]
-++++++View textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="iframe"}, {display="inline"}, {aria-label="Empty iframe"}, {src="frame/empty.html"}, {style="width:100px; height: 100px;"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/iframe-focus-expected-android-assist-data.txt b/content/test/data/accessibility/html/iframe-focus-expected-android-assist-data.txt
index f88a922..736e8ea 100644
--- a/content/test/data/accessibility/html/iframe-focus-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/iframe-focus-expected-android-assist-data.txt
@@ -1,12 +1,12 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="iframe", src="frame/button_onfocus.html", style="width:200px; height: 200px;"]
-++++++View textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++++++++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="button", onfocus="log_focused()", style="margin: 25px; border: 0; width: 250px; height: 50px"]
-++++++++++TextView text:"Button with focus handler" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="focused_log"]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="iframe", src="frame/button.html", style="width:200px; height: 200px;"]
-++++++View textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", style="width: 300px; height: 100px;"]
-++++++++++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="button", style="margin: 25px; border: 0; width: 250px; height: 50px"]
-++++++++++++TextView text:"Ordinary Button" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="iframe"}, {display="inline"}, {src="frame/button_onfocus.html"}, {style="width:200px; height: 200px;"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++++++++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}, {onfocus="log_focused()"}, {style="margin: 25px; border: 0; width: 250px; height: 50px"}]
+++++++++++TextView text:"Button with focus handler" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="focused_log"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="iframe"}, {display="inline"}, {src="frame/button.html"}, {style="width:200px; height: 200px;"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="width: 300px; height: 100px;"}]
+++++++++++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}, {style="margin: 25px; border: 0; width: 250px; height: 50px"}]
+++++++++++++TextView text:"Ordinary Button" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/iframe-traversal-expected-android-assist-data.txt b/content/test/data/accessibility/html/iframe-traversal-expected-android-assist-data.txt
index dd56176..7f33205 100644
--- a/content/test/data/accessibility/html/iframe-traversal-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/iframe-traversal-expected-android-assist-data.txt
@@ -1,12 +1,12 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"Before iframe" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="iframe", src="/accessibility/html/frame/static_text.html"]
-++++++View text:"Error" textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++++++++TextView text:"Could not load the requested resource." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++++View text:"\n" textSize:16.00 style:0 bundle:[display="", htmlTag="br"]
-++++++++++TextView text:"Error code: -6 (net::ERR_FILE_NOT_FOUND)" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"After iframe" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"Before iframe" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="iframe"}, {display="inline"}, {src="/accessibility/html/frame/static_text.html"}]
+++++++View text:"Error" textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++++++++TextView text:"Could not load the requested resource." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++++View text:"\n" textSize:16.0 style:0 htmlInfo:[{htmlTag="br"}, {display=""}]
+++++++++++TextView text:"Error code: -6 (net::ERR_FILE_NOT_FOUND)" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"After iframe" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/img-empty-alt-expected-android-assist-data.txt b/content/test/data/accessibility/html/img-empty-alt-expected-android-assist-data.txt
index 84e0485df..ea91b74 100644
--- a/content/test/data/accessibility/html/img-empty-alt-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/img-empty-alt-expected-android-assist-data.txt
@@ -1,10 +1,10 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++Image text:"read" textSize:16.00 style:0 bundle:[alt="", aria-hidden="false", display="inline", htmlTag="img", src="read.jpg"]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++Image text:"read" textSize:16.00 style:0 bundle:[display="inline", htmlTag="img", src="read.jpg"]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++Image text:"full" textSize:16.00 style:0 bundle:[alt="full", display="inline", htmlTag="img", src="read.jpg"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Image text:"read" textSize:16.0 style:0 htmlInfo:[{htmlTag="img"}, {display="inline"}, {alt=""}, {aria-hidden="false"}, {src="read.jpg"}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Image text:"read" textSize:16.0 style:0 htmlInfo:[{htmlTag="img"}, {display="inline"}, {src="read.jpg"}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Image text:"full" textSize:16.0 style:0 htmlInfo:[{htmlTag="img"}, {display="inline"}, {alt="full"}, {src="read.jpg"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/img-expected-android-assist-data.txt b/content/test/data/accessibility/html/img-expected-android-assist-data.txt
index 2a226980..59ec93e 100644
--- a/content/test/data/accessibility/html/img-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/img-expected-android-assist-data.txt
@@ -1,8 +1,8 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Image text:"pipe" textSize:16.00 style:0 bundle:[alt="pipe", display="inline", htmlTag="img", src="pipe.jpg"]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++Image text:"  " textSize:16.00 style:0 bundle:[alt=" ", display="inline", htmlTag="img", src="pipe.jpg"]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++Image text:"SVG face" textSize:16.00 style:0 bundle:[alt="SVG face", display="inline", htmlTag="img", src="svg-face.svg"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Image text:"pipe" textSize:16.0 style:0 htmlInfo:[{htmlTag="img"}, {display="inline"}, {alt="pipe"}, {src="pipe.jpg"}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Image text:"  " textSize:16.0 style:0 htmlInfo:[{htmlTag="img"}, {display="inline"}, {alt=" "}, {src="pipe.jpg"}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Image text:"SVG face" textSize:16.0 style:0 htmlInfo:[{htmlTag="img"}, {display="inline"}, {alt="SVG face"}, {src="svg-face.svg"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/img-link-empty-alt-expected-android-assist-data.txt b/content/test/data/accessibility/html/img-link-empty-alt-expected-android-assist-data.txt
index 9679a2c5..7fdbde6 100644
--- a/content/test/data/accessibility/html/img-link-empty-alt-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/img-link-empty-alt-expected-android-assist-data.txt
@@ -1,11 +1,11 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="foo", htmlTag="a"]
-++++++TextView text:"unread " textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="foo", htmlTag="a"]
-++++++TextView text:"read " textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="foo", htmlTag="a"]
-++++++TextView text:"read " textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="foo", htmlTag="a"]
-++++++Image text:"read" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", htmlTag="img", src="read.jpg"]
-++++++TextView text:"read" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="foo"}]
+++++++TextView text:"unread " textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="foo"}]
+++++++TextView text:"read " textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="foo"}]
+++++++TextView text:"read " textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="foo"}]
+++++++Image text:"read" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="img"}, {display="inline"}, {src="read.jpg"}]
+++++++TextView text:"read" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/in-page-links-expected-android-assist-data.txt b/content/test/data/accessibility/html/in-page-links-expected-android-assist-data.txt
index d0a3e29..0df0d6d 100644
--- a/content/test/data/accessibility/html/in-page-links-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/in-page-links-expected-android-assist-data.txt
@@ -1,35 +1,35 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#emptyAnchor", htmlTag="a", id="anchor1"]
-++++TextView text:"Empty anchor" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#anchorWithContent", htmlTag="a", id="anchor2"]
-++++TextView text:"Anchor with content" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#anchorWithID", htmlTag="a", id="anchor3"]
-++++TextView text:"Anchor with ID" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#emptySpan", htmlTag="a", id="anchor4"]
-++++TextView text:"Empty span" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#spanWithContent", htmlTag="a", id="anchor5"]
-++++TextView text:"Span with content" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#paragraphWithContent", htmlTag="a", id="anchor6"]
-++++TextView text:"Paragraph with content" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="a", name="emptyAnchor"]
-++++TextView text:"After empty anchor" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="a", name="anchorWithContent"]
-++++++TextView text:"Anchor with content" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="a", id="anchorWithID"]
-++++++TextView text:"Anchor with ID" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="emptySpan"]
-++++TextView text:"After empty span" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="spanWithContent"]
-++++++TextView text:"Span with content" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p", id="paragraphWithContent"]
-++++TextView text:"Paragraph with content" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#emptyAnchor"}, {id="anchor1"}]
+++++TextView text:"Empty anchor" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#anchorWithContent"}, {id="anchor2"}]
+++++TextView text:"Anchor with content" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#anchorWithID"}, {id="anchor3"}]
+++++TextView text:"Anchor with ID" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#emptySpan"}, {id="anchor4"}]
+++++TextView text:"Empty span" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#spanWithContent"}, {id="anchor5"}]
+++++TextView text:"Span with content" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#paragraphWithContent"}, {id="anchor6"}]
+++++TextView text:"Paragraph with content" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="a"}, {display="inline"}, {name="emptyAnchor"}]
+++++TextView text:"After empty anchor" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="a"}, {display="inline"}, {name="anchorWithContent"}]
+++++++TextView text:"Anchor with content" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="a"}, {display="inline"}, {id="anchorWithID"}]
+++++++TextView text:"Anchor with ID" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="emptySpan"}]
+++++TextView text:"After empty span" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="spanWithContent"}]
+++++++TextView text:"Span with content" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {id="paragraphWithContent"}]
+++++TextView text:"Paragraph with content" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-button-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-button-expected-android-assist-data.txt
index 1cf7cc62..0f4c9763 100644
--- a/content/test/data/accessibility/html/input-button-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-button-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Button text:"Button" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="input", type="button", value="Button"]
-++++++TextView text:"Button" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++++Button text:"Name Description" textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-label="Name", display="inline-block", htmlTag="input", type="button", value="Description"]
-++++++TextView text:"Description" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Button text:"Button" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="button"}, {value="Button"}]
+++++++TextView text:"Button" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Button text:"Name Description" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-label="Name"}, {type="button"}, {value="Description"}]
+++++++TextView text:"Description" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-checkbox-label-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-checkbox-label-expected-android-assist-data.txt
index 2c75d93..a3aad10 100644
--- a/content/test/data/accessibility/html/input-checkbox-label-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-checkbox-label-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++CheckBox text:"Checkbox Title" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", type="checkbox"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++CheckBox text:"Checkbox Title" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="checkbox"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-color-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-color-expected-android-assist-data.txt
index 72f0fbf2..50bc65b 100644
--- a/content/test/data/accessibility/html/input-color-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-color-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Spinner text:"#FF9900" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="input", type="color", value="#ff9900"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Spinner text:"#FF9900" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="color"}, {value="#ff9900"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-color-with-popup-open-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-color-with-popup-open-expected-android-assist-data.txt
index 44854f8..9cbf270 100644
--- a/content/test/data/accessibility/html/input-color-with-popup-open-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-color-with-popup-open-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Spinner text:"#FF9900" textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-label="color picker", display="inline-block", htmlTag="input", type="color", value="#ff9900"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Spinner text:"#FF9900" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-label="color picker"}, {type="color"}, {value="#ff9900"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-date-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-date-expected-android-assist-data.txt
index 6ef2382..aa25f23 100644
--- a/content/test/data/accessibility/html/input-date-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-date-expected-android-assist-data.txt
@@ -1,8 +1,8 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Spinner text:"2008-09-01" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-flex", htmlTag="input", type="date", value="2008-09-01"]
-++++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div", pseudo="-webkit-date-and-time-value"]
-++++++++TextView text:"09/01/2008" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++++Spinner text:"When" textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-label="When", display="inline-flex", htmlTag="input", type="date", value="2008-09-01"]
-++++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div", pseudo="-webkit-date-and-time-value"]
-++++++++TextView text:"09/01/2008" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Spinner text:"2008-09-01" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-flex"}, {type="date"}, {value="2008-09-01"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {pseudo="-webkit-date-and-time-value"}]
+++++++++TextView text:"09/01/2008" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Spinner text:"When" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-flex"}, {aria-label="When"}, {type="date"}, {value="2008-09-01"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {pseudo="-webkit-date-and-time-value"}]
+++++++++TextView text:"09/01/2008" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-date-with-popup-open-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-date-with-popup-open-expected-android-assist-data.txt
index 89fcd46..ba23cb4 100644
--- a/content/test/data/accessibility/html/input-date-with-popup-open-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-date-with-popup-open-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Spinner text:"2008-09-01" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-flex", htmlTag="input", type="date", value="2008-09-01"]
-++++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div", pseudo="-webkit-date-and-time-value"]
-++++++++TextView text:"09/01/2008" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Spinner text:"2008-09-01" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-flex"}, {type="date"}, {value="2008-09-01"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {pseudo="-webkit-date-and-time-value"}]
+++++++++TextView text:"09/01/2008" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-date-with-popup-open-multiple-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-date-with-popup-open-multiple-expected-android-assist-data.txt
index 83651beb..86c7633 100644
--- a/content/test/data/accessibility/html/input-date-with-popup-open-multiple-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-date-with-popup-open-multiple-expected-android-assist-data.txt
@@ -1,11 +1,11 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Spinner text:"2008-09-01" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-flex", htmlTag="input", type="date", value="2008-09-01"]
-++++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div", pseudo="-webkit-date-and-time-value"]
-++++++++TextView text:"09/01/2008" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++++Spinner text:"2008-09-01" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-flex", htmlTag="input", type="date", value="2008-09-01"]
-++++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div", pseudo="-webkit-date-and-time-value"]
-++++++++TextView text:"09/01/2008" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++++Spinner text:"Third date picker" textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-label="Third date picker", display="inline-flex", htmlTag="input", type="date", value="2008-09-01"]
-++++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div", pseudo="-webkit-date-and-time-value"]
-++++++++TextView text:"09/01/2008" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Spinner text:"2008-09-01" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-flex"}, {type="date"}, {value="2008-09-01"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {pseudo="-webkit-date-and-time-value"}]
+++++++++TextView text:"09/01/2008" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Spinner text:"2008-09-01" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-flex"}, {type="date"}, {value="2008-09-01"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {pseudo="-webkit-date-and-time-value"}]
+++++++++TextView text:"09/01/2008" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Spinner text:"Third date picker" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-flex"}, {aria-label="Third date picker"}, {type="date"}, {value="2008-09-01"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {pseudo="-webkit-date-and-time-value"}]
+++++++++TextView text:"09/01/2008" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-date-with-popup-open-multiple-for-win-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-date-with-popup-open-multiple-for-win-expected-android-assist-data.txt
index 83651beb..86c7633 100644
--- a/content/test/data/accessibility/html/input-date-with-popup-open-multiple-for-win-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-date-with-popup-open-multiple-for-win-expected-android-assist-data.txt
@@ -1,11 +1,11 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Spinner text:"2008-09-01" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-flex", htmlTag="input", type="date", value="2008-09-01"]
-++++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div", pseudo="-webkit-date-and-time-value"]
-++++++++TextView text:"09/01/2008" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++++Spinner text:"2008-09-01" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-flex", htmlTag="input", type="date", value="2008-09-01"]
-++++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div", pseudo="-webkit-date-and-time-value"]
-++++++++TextView text:"09/01/2008" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++++Spinner text:"Third date picker" textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-label="Third date picker", display="inline-flex", htmlTag="input", type="date", value="2008-09-01"]
-++++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div", pseudo="-webkit-date-and-time-value"]
-++++++++TextView text:"09/01/2008" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Spinner text:"2008-09-01" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-flex"}, {type="date"}, {value="2008-09-01"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {pseudo="-webkit-date-and-time-value"}]
+++++++++TextView text:"09/01/2008" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Spinner text:"2008-09-01" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-flex"}, {type="date"}, {value="2008-09-01"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {pseudo="-webkit-date-and-time-value"}]
+++++++++TextView text:"09/01/2008" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Spinner text:"Third date picker" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-flex"}, {aria-label="Third date picker"}, {type="date"}, {value="2008-09-01"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {pseudo="-webkit-date-and-time-value"}]
+++++++++TextView text:"09/01/2008" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-datetime-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-datetime-expected-android-assist-data.txt
index d2e30e2..5d2e98c52 100644
--- a/content/test/data/accessibility/html/input-datetime-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-datetime-expected-android-assist-data.txt
@@ -1,8 +1,8 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++EditText text:"1/1/2015 1:00AM" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", type="datetime", value="1/1/2015 1:00AM"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++++++TextView text:"1/1/2015 1:00AM" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++++EditText text:"1/1/2015 1:00AM" textSize:13.33 style:0 bundle:[aria-label="Launch", display="inline-block", htmlTag="input", type="datetime", value="1/1/2015 1:00AM"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++++++TextView text:"1/1/2015 1:00AM" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++EditText text:"1/1/2015 1:00AM" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="datetime"}, {value="1/1/2015 1:00AM"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++++++TextView text:"1/1/2015 1:00AM" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++EditText text:"1/1/2015 1:00AM" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-label="Launch"}, {type="datetime"}, {value="1/1/2015 1:00AM"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++++++TextView text:"1/1/2015 1:00AM" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-datetime-local-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-datetime-local-expected-android-assist-data.txt
index 0a76c46..656c623d 100644
--- a/content/test/data/accessibility/html/input-datetime-local-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-datetime-local-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Spinner text:" " textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-flex", htmlTag="input", type="datetime-local"]
-++++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div", pseudo="-webkit-date-and-time-value"]
-++++++++TextView text:" " textSize:13.33 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Spinner text:" " textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-flex"}, {type="datetime-local"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {pseudo="-webkit-date-and-time-value"}]
+++++++++TextView text:" " textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-email-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-email-expected-android-assist-data.txt
index 11c3b56..1878c1c6c 100644
--- a/content/test/data/accessibility/html/input-email-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-email-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++EditText text:"someone@example.com" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", type="email", value="someone@example.com"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++++++TextView text:"someone@example.com" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++EditText text:"someone@example.com" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="email"}, {value="someone@example.com"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++++++TextView text:"someone@example.com" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-file-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-file-expected-android-assist-data.txt
index 2b7ba41..ba2926a 100644
--- a/content/test/data/accessibility/html/input-file-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-file-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Button textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", type="file"]
-++++++Button text:"Choose File" textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-hidden="true", display="inline-block", htmlTag="input", id="file-upload-button", pseudo="-webkit-file-upload-button", type="button", value="Choose File"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Button textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="file"}]
+++++++Button text:"Choose File" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-hidden="true"}, {id="file-upload-button"}, {pseudo="-webkit-file-upload-button"}, {type="button"}, {value="Choose File"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-image-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-image-expected-android-assist-data.txt
index 721c8c35..66972f7 100644
--- a/content/test/data/accessibility/html/input-image-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-image-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body", id="body"]
-++++Button text:"Submit" textSize:13.33 style:0 bundle:[alt="Submit", display="inline-block", height="100", htmlTag="input", src="greenbox.png", type="image", width="100"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}, {id="body"}]
+++++Button text:"Submit" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {alt="Submit"}, {height="100"}, {src="greenbox.png"}, {type="image"}, {width="100"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-list-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-list-expected-android-assist-data.txt
index 517efa1f0..d4aa3eb 100644
--- a/content/test/data/accessibility/html/input-list-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-list-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="label"]
-++++++TextView text:"Choose a pokemon " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++EditText text:"Choose a pokemon" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", list="pokemon"]
-++++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="label"}, {display="inline"}]
+++++++TextView text:"Choose a pokemon " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++EditText text:"Choose a pokemon" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {list="pokemon"}]
+++++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-month-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-month-expected-android-assist-data.txt
index c4f5789..f1937af 100644
--- a/content/test/data/accessibility/html/input-month-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-month-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Spinner text:" " textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-flex", htmlTag="input", type="month"]
-++++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div", pseudo="-webkit-date-and-time-value"]
-++++++++TextView text:" " textSize:13.33 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Spinner text:" " textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-flex"}, {type="month"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {pseudo="-webkit-date-and-time-value"}]
+++++++++TextView text:" " textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-number-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-number-expected-android-assist-data.txt
index a69fa1c..eb9f256 100644
--- a/content/test/data/accessibility/html/input-number-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-number-expected-android-assist-data.txt
@@ -1,8 +1,8 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++EditText text:"1" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", type="number", value="1"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++++++TextView text:"1" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++++EditText text:"6" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", max="10", min="5", type="number", value="6"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++++++TextView text:"6" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++EditText text:"1" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="number"}, {value="1"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++++++TextView text:"1" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++EditText text:"6" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {max="10"}, {min="5"}, {type="number"}, {value="6"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++++++TextView text:"6" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-password-obscured-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-password-obscured-expected-android-assist-data.txt
index b3b39b06..69929e3 100644
--- a/content/test/data/accessibility/html/input-password-obscured-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-password-obscured-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++EditText text:"•••" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", id="input", type="password", value="foo"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++++++TextView text:"•••" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++EditText text:"•••" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {id="input"}, {type="password"}, {value="foo"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++++++TextView text:"•••" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-radio-checkbox-label-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-radio-checkbox-label-expected-android-assist-data.txt
index 13c3953..c2c1bc8b 100644
--- a/content/test/data/accessibility/html/input-radio-checkbox-label-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-radio-checkbox-label-expected-android-assist-data.txt
@@ -1,10 +1,10 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++RadioButton text:"label ignored for radio button" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", id="radio1", type="radio"]
-++++CheckBox text:"label ignored for checkbox" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", id="checkbox1", type="checkbox"]
-++++View textSize:16.00 style:0 bundle:[display="inline", for="radio2", htmlTag="label", tabindex="0"]
-++++++TextView text:"label exposed for radio button " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++RadioButton text:"label exposed for radio button" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", id="radio2", tabindex="-1", type="radio"]
-++++View textSize:16.00 style:0 bundle:[display="inline", for="checkbox2", htmlTag="label", tabindex="0"]
-++++++TextView text:"label exposed for checkbox " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++CheckBox text:"label exposed for checkbox" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", id="checkbox2", tabindex="-1", type="checkbox"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++RadioButton text:"label ignored for radio button" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {id="radio1"}, {type="radio"}]
+++++CheckBox text:"label ignored for checkbox" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {id="checkbox1"}, {type="checkbox"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="label"}, {display="inline"}, {for="radio2"}, {tabindex="0"}]
+++++++TextView text:"label exposed for radio button " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++RadioButton text:"label exposed for radio button" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {id="radio2"}, {tabindex="-1"}, {type="radio"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="label"}, {display="inline"}, {for="checkbox2"}, {tabindex="0"}]
+++++++TextView text:"label exposed for checkbox " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++CheckBox text:"label exposed for checkbox" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {id="checkbox2"}, {tabindex="-1"}, {type="checkbox"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-radio-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-radio-expected-android-assist-data.txt
index e8bf9b56..befe40a 100644
--- a/content/test/data/accessibility/html/input-radio-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-radio-expected-android-assist-data.txt
@@ -1,13 +1,13 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="form"]
-++++RadioButton textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", name="r1", type="radio", value="r1"]
-++++TextView text:"Radio1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View text:"\n" textSize:16.00 style:0 bundle:[display="", htmlTag="br"]
-++++RadioButton textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", name="r2", type="radio", value="r2"]
-++++TextView text:"Radio2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="form"]
-++++RadioButton text:"Radio3" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", name="rGroup", type="radio", value="r3"]
-++++RadioButton text:"Radio4" textSize:13.33 style:0 bundle:[checked="", display="inline-block", htmlTag="input", name="rGroup", type="radio", value="r4"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="form"]
-++++RadioButton text:"Radio5" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", name="r1", type="radio", value="r3"]
-++++RadioButton text:"Radio6" textSize:13.33 style:0 bundle:[checked="", display="inline-block", htmlTag="input", name="r2", type="radio", value="r4"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="form"}, {display="block"}]
+++++RadioButton textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {name="r1"}, {type="radio"}, {value="r1"}]
+++++TextView text:"Radio1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View text:"\n" textSize:16.0 style:0 htmlInfo:[{htmlTag="br"}, {display=""}]
+++++RadioButton textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {name="r2"}, {type="radio"}, {value="r2"}]
+++++TextView text:"Radio2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="form"}, {display="block"}]
+++++RadioButton text:"Radio3" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {name="rGroup"}, {type="radio"}, {value="r3"}]
+++++RadioButton text:"Radio4" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {checked=""}, {name="rGroup"}, {type="radio"}, {value="r4"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="form"}, {display="block"}]
+++++RadioButton text:"Radio5" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {name="r1"}, {type="radio"}, {value="r3"}]
+++++RadioButton text:"Radio6" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {checked=""}, {name="r2"}, {type="radio"}, {value="r4"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-radio-in-menu-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-radio-in-menu-expected-android-assist-data.txt
index 4a35b99..db34d3c 100644
--- a/content/test/data/accessibility/html/input-radio-in-menu-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-radio-in-menu-expected-android-assist-data.txt
@@ -1,11 +1,11 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="menu"]
-++++RadioButton textSize:13.33 style:0 bundle:[checked="", display="inline-block", htmlTag="input", name="rg1", type="radio", value="r0"]
-++++TextView text:"Radio0 " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++RadioButton textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", name="rg1", type="radio", value="r1"]
-++++TextView text:"Radio1 " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++RadioButton text:"Radio2" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", name="rg1", type="radio", value="r2"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="menu"]
-++++RadioButton text:"Radio3" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", name="rg2", type="radio", value="r3"]
-++++RadioButton textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", name="rg2", type="radio", value="r4"]
-++++RadioButton textSize:13.33 style:0 bundle:[checked="", display="inline-block", htmlTag="input", name="rg2", type="radio", value="r5"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="menu"}]
+++++RadioButton textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {checked=""}, {name="rg1"}, {type="radio"}, {value="r0"}]
+++++TextView text:"Radio0 " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++RadioButton textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {name="rg1"}, {type="radio"}, {value="r1"}]
+++++TextView text:"Radio1 " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++RadioButton text:"Radio2" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {name="rg1"}, {type="radio"}, {value="r2"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="menu"}]
+++++RadioButton text:"Radio3" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {name="rg2"}, {type="radio"}, {value="r3"}]
+++++RadioButton textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {name="rg2"}, {type="radio"}, {value="r4"}]
+++++RadioButton textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {checked=""}, {name="rg2"}, {type="radio"}, {value="r5"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-range-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-range-expected-android-assist-data.txt
index 040ab6a4..7cd31f5 100644
--- a/content/test/data/accessibility/html/input-range-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-range-expected-android-assist-data.txt
@@ -1,8 +1,8 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++SeekBar textSize:13.33 style:0 fgColor:-6449522 bundle:[display="inline-block", htmlTag="input", max="10", min="1", type="range", value="5"]
-++++SeekBar textSize:13.33 style:0 fgColor:-6449522 bundle:[aria-valuenow="3", display="inline-block", htmlTag="input", max="10", min="1", type="range", value="5"]
-++++SeekBar text:"Medium" textSize:13.33 style:0 fgColor:-6449522 bundle:[aria-valuetext="Medium", display="inline-block", htmlTag="input", max="10", min="1", type="range", value="5"]
-++++SeekBar text:"Friday" textSize:13.33 style:0 fgColor:-6449522 bundle:[aria-valuenow="6", aria-valuetext="Friday", display="inline-block", htmlTag="input", max="5", min="0", type="range", value="2"]
-++++SeekBar textSize:13.33 style:0 fgColor:-6449522 bundle:[display="inline-block", htmlTag="input", max="1", min="-1", step="0.1", type="range", value="0.2"]
-++++SeekBar textSize:13.33 style:0 fgColor:-6449522 bundle:[display="inline-block", htmlTag="input", max="100", min="0", step="1", type="range"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++SeekBar textSize:13.3 style:0 fgColor:-6449522 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {max="10"}, {min="1"}, {type="range"}, {value="5"}]
+++++SeekBar textSize:13.3 style:0 fgColor:-6449522 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-valuenow="3"}, {max="10"}, {min="1"}, {type="range"}, {value="5"}]
+++++SeekBar text:"Medium" textSize:13.3 style:0 fgColor:-6449522 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-valuetext="Medium"}, {max="10"}, {min="1"}, {type="range"}, {value="5"}]
+++++SeekBar text:"Friday" textSize:13.3 style:0 fgColor:-6449522 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-valuenow="6"}, {aria-valuetext="Friday"}, {max="5"}, {min="0"}, {type="range"}, {value="2"}]
+++++SeekBar textSize:13.3 style:0 fgColor:-6449522 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {max="1"}, {min="-1"}, {step="0.1"}, {type="range"}, {value="0.2"}]
+++++SeekBar textSize:13.3 style:0 fgColor:-6449522 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {max="100"}, {min="0"}, {step="1"}, {type="range"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-reset-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-reset-expected-android-assist-data.txt
index 2bb9d6df..dc242a7 100644
--- a/content/test/data/accessibility/html/input-reset-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-reset-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++EditText textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", type="text"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++Button text:"Reset" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="input", type="reset", value="Reset"]
-++++++TextView text:"Reset" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="text"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++Button text:"Reset" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="reset"}, {value="Reset"}]
+++++++TextView text:"Reset" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-search-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-search-expected-android-assist-data.txt
index 970b56c..9bee609 100644
--- a/content/test/data/accessibility/html/input-search-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-search-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++EditText text:"Search terms" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", name="googlesearch", type="search", value="Search terms"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++++++TextView text:"Search terms" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++EditText text:"Search terms" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {name="googlesearch"}, {type="search"}, {value="Search terms"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++++++TextView text:"Search terms" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-submit-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-submit-expected-android-assist-data.txt
index 9fb90724..d8b8b22a8 100644
--- a/content/test/data/accessibility/html/input-submit-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-submit-expected-android-assist-data.txt
@@ -1,20 +1,20 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="form"]
-++++EditText textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", name="Name", type="text"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++Button text:"First submit in a form is a valid default button" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="input", type="submit", value="First submit  in a form is a valid default button"]
-++++++TextView text:"First submit  in a form is a valid default button" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++++Button text:"Second submit in a form not a valid default button" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="input", type="submit", value="Second submit in a form not a valid default button"]
-++++++TextView text:"Second submit in a form not a valid default button" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="form"]
-++++EditText textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", name="Name", type="text"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++Button text:"First image button in a form is a valid default button" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", type="image", value="First image button in a form is a valid default button"]
-++++++Image textSize:13.33 style:0 bundle:[align="left", display="block", height="16", htmlTag="img", id="alttext-image", style="margin: 0px; display: inline; float: left;", width="16"]
-++++++TextView text:"First image button in a form is a valid default button" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++Button text:"Second image button in a form not a valid default button" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", type="image", value="Second image button in a form not a valid default button"]
-++++++Image textSize:13.33 style:0 bundle:[align="left", display="block", height="16", htmlTag="img", id="alttext-image", style="margin: 0px; display: inline; float: left;", width="16"]
-++++++TextView text:"Second image button in a form not a valid default button" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++Button text:"Submit outside of form not a valid default button" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="input", type="submit", value="Submit outside of form not a valid default button"]
-++++TextView text:"Submit outside of form not a valid default button" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="form"}, {display="block"}]
+++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {name="Name"}, {type="text"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++Button text:"First submit in a form is a valid default button" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="submit"}, {value="First submit  in a form is a valid default button"}]
+++++++TextView text:"First submit  in a form is a valid default button" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Button text:"Second submit in a form not a valid default button" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="submit"}, {value="Second submit in a form not a valid default button"}]
+++++++TextView text:"Second submit in a form not a valid default button" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="form"}, {display="block"}]
+++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {name="Name"}, {type="text"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++Button text:"First image button in a form is a valid default button" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="image"}, {value="First image button in a form is a valid default button"}]
+++++++Image textSize:13.3 style:0 htmlInfo:[{htmlTag="img"}, {display="block"}, {align="left"}, {height="16"}, {id="alttext-image"}, {style="margin: 0px; display: inline; float: left;"}, {width="16"}]
+++++++TextView text:"First image button in a form is a valid default button" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Button text:"Second image button in a form not a valid default button" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="image"}, {value="Second image button in a form not a valid default button"}]
+++++++Image textSize:13.3 style:0 htmlInfo:[{htmlTag="img"}, {display="block"}, {align="left"}, {height="16"}, {id="alttext-image"}, {style="margin: 0px; display: inline; float: left;"}, {width="16"}]
+++++++TextView text:"Second image button in a form not a valid default button" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button text:"Submit outside of form not a valid default button" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="submit"}, {value="Submit outside of form not a valid default button"}]
+++++TextView text:"Submit outside of form not a valid default button" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-suggestions-source-element-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-suggestions-source-element-expected-android-assist-data.txt
index 1580524..1f39a0d 100644
--- a/content/test/data/accessibility/html/input-suggestions-source-element-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-suggestions-source-element-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++EditText textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", list="datalist1", type="text"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {list="datalist1"}, {type="text"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-tel-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-tel-expected-android-assist-data.txt
index 97ebeab..7b9e729 100644
--- a/content/test/data/accessibility/html/input-tel-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-tel-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++EditText text:"123-456-7890" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", type="tel", value="123-456-7890"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++++++TextView text:"123-456-7890" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++EditText text:"123-456-7890" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="tel"}, {value="123-456-7890"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++++++TextView text:"123-456-7890" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-text-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-text-expected-android-assist-data.txt
index 46365174..71bcc4e 100644
--- a/content/test/data/accessibility/html/input-text-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-text-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++EditText text:"Name" textSize:13.33 style:0 bundle:[autofocus="", display="inline-block", htmlTag="input", placeholder="Name", type="text"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++EditText text:"Name" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {autofocus=""}, {placeholder="Name"}, {type="text"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-text-name-calc-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-text-name-calc-expected-android-assist-data.txt
index 8afccc8..c473b09 100644
--- a/content/test/data/accessibility/html/input-text-name-calc-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-text-name-calc-expected-android-assist-data.txt
@@ -1,45 +1,45 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++EditText text:"Title0" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", id="c0", title="Title0", type="text"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++EditText text:"Label1 Title1" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", id="c1", title="Title1", type="text"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++EditText text:"AriaLabel2 Title2" textSize:13.33 style:0 bundle:[aria-label="AriaLabel2", display="inline-block", htmlTag="input", id="c2", title="Title2", type="text"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++EditText text:"LabelledBy3 Title3" textSize:13.33 style:0 bundle:[aria-label="AriaLabel3", aria-labelledby="lb3", display="inline-block", htmlTag="input", id="c3", title="Title3", type="text"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++EditText text:"Placeholder4" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", id="c4", placeholder="Placeholder4", type="text"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++EditText text:"ARIA Placeholder4a" textSize:13.33 style:0 bundle:[aria-placeholder="ARIA Placeholder4a", display="inline-block", htmlTag="input", id="c4a", type="text"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++EditText text:"Placeholder4b" textSize:13.33 style:0 bundle:[aria-placeholder="ARIA Placeholder4b", display="inline-block", htmlTag="input", id="c4b", placeholder="Placeholder4b", type="text"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++EditText text:"Title5" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", id="c5", placeholder="Placeholder5", title="Title5", type="text"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++EditText text:"LabelledBy6 DescribedBy6" textSize:13.33 style:0 bundle:[aria-describedby="db6", aria-label="AriaLabel6", aria-labelledby="lb6", display="inline-block", htmlTag="input", id="c6", title="Title6", type="text"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++EditText text:"AriaLabel7 DescribedBy7" textSize:13.33 style:0 bundle:[aria-describedby="db7", aria-label="AriaLabel7", display="inline-block", htmlTag="input", id="c7", placeholder="Placeholder7", type="text"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++View textSize:16.00 style:0 bundle:[class="@NO_DUMP", display="block", htmlTag="p"]
-++++View textSize:16.00 style:0 bundle:[display="inline", for="c1", htmlTag="label"]
-++++++TextView text:"Label1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", for="c2", htmlTag="label"]
-++++++TextView text:"Label2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", for="c3", htmlTag="label"]
-++++++TextView text:"Label3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", for="c6", htmlTag="label"]
-++++++TextView text:"Label6" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="lb3"]
-++++++TextView text:"LabelledBy3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="lb6"]
-++++++TextView text:"LabelledBy6" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="db6"]
-++++++TextView text:"DescribedBy6" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="db7"]
-++++++TextView text:"DescribedBy7" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++EditText text:"Title0" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {id="c0"}, {title="Title0"}, {type="text"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++EditText text:"Label1 Title1" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {id="c1"}, {title="Title1"}, {type="text"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++EditText text:"AriaLabel2 Title2" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-label="AriaLabel2"}, {id="c2"}, {title="Title2"}, {type="text"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++EditText text:"LabelledBy3 Title3" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-label="AriaLabel3"}, {aria-labelledby="lb3"}, {id="c3"}, {title="Title3"}, {type="text"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++EditText text:"Placeholder4" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {id="c4"}, {placeholder="Placeholder4"}, {type="text"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++EditText text:"ARIA Placeholder4a" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-placeholder="ARIA Placeholder4a"}, {id="c4a"}, {type="text"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++EditText text:"Placeholder4b" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-placeholder="ARIA Placeholder4b"}, {id="c4b"}, {placeholder="Placeholder4b"}, {type="text"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++EditText text:"Title5" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {id="c5"}, {placeholder="Placeholder5"}, {title="Title5"}, {type="text"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++EditText text:"LabelledBy6 DescribedBy6" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-describedby="db6"}, {aria-label="AriaLabel6"}, {aria-labelledby="lb6"}, {id="c6"}, {title="Title6"}, {type="text"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++EditText text:"AriaLabel7 DescribedBy7" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-describedby="db7"}, {aria-label="AriaLabel7"}, {id="c7"}, {placeholder="Placeholder7"}, {type="text"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {class="@NO_DUMP"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="label"}, {display="inline"}, {for="c1"}]
+++++++TextView text:"Label1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="label"}, {display="inline"}, {for="c2"}]
+++++++TextView text:"Label2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="label"}, {display="inline"}, {for="c3"}]
+++++++TextView text:"Label3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="label"}, {display="inline"}, {for="c6"}]
+++++++TextView text:"Label6" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="lb3"}]
+++++++TextView text:"LabelledBy3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="lb6"}]
+++++++TextView text:"LabelledBy6" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="db6"}]
+++++++TextView text:"DescribedBy6" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="db7"}]
+++++++TextView text:"DescribedBy7" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-text-range-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-text-range-expected-android-assist-data.txt
index 57ef65a..33235558 100644
--- a/content/test/data/accessibility/html/input-text-range-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-text-range-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++SeekBar text:"medium" textSize:13.33 style:0 fgColor:-6449522 bundle:[aria-valuetext="medium", display="inline-block", htmlTag="input", max="2", min="0", type="range", value="1"]
-++++View textSize:16.00 style:0 bundle:[display="inline", for="in2", htmlTag="label"]
-++++++TextView text:"This is a test label " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++SeekBar text:"small" textSize:13.33 style:0 fgColor:-6449522 bundle:[aria-valuetext="small", display="inline-block", htmlTag="input", max="2", min="0", type="range", value="0"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++SeekBar text:"medium" textSize:13.3 style:0 fgColor:-6449522 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-valuetext="medium"}, {max="2"}, {min="0"}, {type="range"}, {value="1"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="label"}, {display="inline"}, {for="in2"}]
+++++++TextView text:"This is a test label " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++SeekBar text:"small" textSize:13.3 style:0 fgColor:-6449522 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-valuetext="small"}, {max="2"}, {min="0"}, {type="range"}, {value="0"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-text-read-only-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-text-read-only-expected-android-assist-data.txt
index cea6ec5a..6a7eab27 100644
--- a/content/test/data/accessibility/html/input-text-read-only-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-text-read-only-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++EditText text:"Name" textSize:13.33 style:0 bundle:[autofocus="", display="inline-block", htmlTag="input", placeholder="Name", readonly="", type="text"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++EditText text:"Name" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {autofocus=""}, {placeholder="Name"}, {readonly=""}, {type="text"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-text-value-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-text-value-expected-android-assist-data.txt
index 9df524bc..e14c2ff 100644
--- a/content/test/data/accessibility/html/input-text-value-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-text-value-expected-android-assist-data.txt
@@ -1,32 +1,32 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:13.00 style:0 bundle:[display="block", htmlTag="body", style="font-family:monospace;width:999px"]
-++++View textSize:13.00 style:0 bundle:[display="inline", for="i1", htmlTag="label"]
-++++++TextView text:"l1" textSize:13.00 style:0 bundle:[display="", htmlTag=""]
-++++EditText text:"l1" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", id="i1"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++View textSize:13.00 style:0 bundle:[display="inline", for="i2", htmlTag="label"]
-++++++TextView text:"l2" textSize:13.00 style:0 bundle:[display="", htmlTag=""]
-++++EditText text:"value" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", id="i2", value="value"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++++++TextView text:"value" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++++EditText text:"l2" textSize:13.33 style:0 bundle:[aria-label="l2", display="inline-block", htmlTag="input"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++EditText text:"value  *" textSize:13.33 style:0 bundle:[aria-label="l2", display="inline-block", htmlTag="input", value="value  *"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++++++TextView text:"value  *" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:13.00 style:0 bundle:[display="inline", htmlTag="label", id="l3"]
-++++++TextView text:"Email" textSize:13.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:13.00 style:0 bundle:[display="inline", htmlTag="span", id="l4"]
-++++EditText text:"Email" textSize:13.33 style:0 bundle:[aria-labelledby="l3 42", display="inline-block", htmlTag="input"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++EditText text:"value" textSize:13.33 style:0 bundle:[aria-labelledby="l3 l4", display="inline-block", htmlTag="input", value="value"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++++++TextView text:"value" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++++EditText text:"l5" textSize:13.33 style:0 bundle:[aria-label="l5", display="inline-block", htmlTag="textarea"]
-++++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div"]
-++++EditText text:"Value" textSize:13.33 style:0 bundle:[aria-label="l6", display="inline-block", htmlTag="textarea"]
-++++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div"]
-++++++++TextView text:"Value" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++++EditText text:"value" textSize:13.33 style:0 bundle:[aria-label="Name", display="inline-block", htmlTag="input", title="Description", value="value"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++++++TextView text:"value" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:13.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}, {style="font-family:monospace;width:999px"}]
+++++View textSize:13.0 style:0 htmlInfo:[{htmlTag="label"}, {display="inline"}, {for="i1"}]
+++++++TextView text:"l1" textSize:13.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++EditText text:"l1" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {id="i1"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++View textSize:13.0 style:0 htmlInfo:[{htmlTag="label"}, {display="inline"}, {for="i2"}]
+++++++TextView text:"l2" textSize:13.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++EditText text:"value" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {id="i2"}, {value="value"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++++++TextView text:"value" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++EditText text:"l2" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-label="l2"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++EditText text:"value  *" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-label="l2"}, {value="value  *"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++++++TextView text:"value  *" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:13.0 style:0 htmlInfo:[{htmlTag="label"}, {display="inline"}, {id="l3"}]
+++++++TextView text:"Email" textSize:13.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:13.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="l4"}]
+++++EditText text:"Email" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-labelledby="l3 42"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++EditText text:"value" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-labelledby="l3 l4"}, {value="value"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++++++TextView text:"value" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++EditText text:"l5" textSize:13.3 style:0 htmlInfo:[{htmlTag="textarea"}, {display="inline-block"}, {aria-label="l5"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++EditText text:"Value" textSize:13.3 style:0 htmlInfo:[{htmlTag="textarea"}, {display="inline-block"}, {aria-label="l6"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++++++TextView text:"Value" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++EditText text:"value" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-label="Name"}, {title="Description"}, {value="value"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++++++TextView text:"value" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-time-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-time-expected-android-assist-data.txt
index efe461fd..abbaaf69 100644
--- a/content/test/data/accessibility/html/input-time-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-time-expected-android-assist-data.txt
@@ -1,8 +1,8 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Spinner text:"00:00:00" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-flex", htmlTag="input", type="time", value="00:00:00"]
-++++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div", pseudo="-webkit-date-and-time-value"]
-++++++++TextView text:"12:00 AM" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++++Spinner text:"Breakfast" textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-label="Breakfast", display="inline-flex", htmlTag="input", type="time", value="00:00:00"]
-++++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div", pseudo="-webkit-date-and-time-value"]
-++++++++TextView text:"12:00 AM" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Spinner text:"00:00:00" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-flex"}, {type="time"}, {value="00:00:00"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {pseudo="-webkit-date-and-time-value"}]
+++++++++TextView text:"12:00 AM" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Spinner text:"Breakfast" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-flex"}, {aria-label="Breakfast"}, {type="time"}, {value="00:00:00"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {pseudo="-webkit-date-and-time-value"}]
+++++++++TextView text:"12:00 AM" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-time-with-popup-open-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-time-with-popup-open-expected-android-assist-data.txt
index bb23e7fd..b931dc7 100644
--- a/content/test/data/accessibility/html/input-time-with-popup-open-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-time-with-popup-open-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Spinner text:"13:50:02.922" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-flex", htmlTag="input", type="time", value="13:50:02.922"]
-++++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div", pseudo="-webkit-date-and-time-value"]
-++++++++TextView text:"1:50:02.922 PM" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Spinner text:"13:50:02.922" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-flex"}, {type="time"}, {value="13:50:02.922"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {pseudo="-webkit-date-and-time-value"}]
+++++++++TextView text:"1:50:02.922 PM" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-url-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-url-expected-android-assist-data.txt
index c80d6f4..93e360f 100644
--- a/content/test/data/accessibility/html/input-url-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-url-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++EditText text:"example.com" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", type="url", value="example.com"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++++++TextView text:"example.com" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++EditText text:"example.com" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="url"}, {value="example.com"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++++++TextView text:"example.com" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-week-expected-android-assist-data.txt b/content/test/data/accessibility/html/input-week-expected-android-assist-data.txt
index 2ecea43..33ec124 100644
--- a/content/test/data/accessibility/html/input-week-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/input-week-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Spinner text:" " textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-flex", htmlTag="input", type="week"]
-++++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div", pseudo="-webkit-date-and-time-value"]
-++++++++TextView text:" " textSize:13.33 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Spinner text:" " textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-flex"}, {type="week"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {pseudo="-webkit-date-and-time-value"}]
+++++++++TextView text:" " textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/ins-expected-android-assist-data.txt b/content/test/data/accessibility/html/ins-expected-android-assist-data.txt
index 9a7df66..7880ba3 100644
--- a/content/test/data/accessibility/html/ins-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/ins-expected-android-assist-data.txt
@@ -1,9 +1,9 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:8.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"My favorite browser is " textSize:8.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:8.00 style:8 bundle:[display="inline", htmlTag="del"]
-++++++TextView text:"ABC" textSize:8.00 style:8 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:8.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:8.00 style:4 bundle:[display="inline", htmlTag="ins"]
-++++++TextView text:"Chrome" textSize:8.00 style:4 bundle:[display="", htmlTag=""]
-++++TextView text:"!" textSize:8.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:8.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"My favorite browser is " textSize:8.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:8.0 style:8 htmlInfo:[{htmlTag="del"}, {display="inline"}]
+++++++TextView text:"ABC" textSize:8.0 style:8 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:8.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:8.0 style:4 htmlInfo:[{htmlTag="ins"}, {display="inline"}]
+++++++TextView text:"Chrome" textSize:8.0 style:4 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"!" textSize:8.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/interactive-controls-with-labels-expected-android-assist-data.txt b/content/test/data/accessibility/html/interactive-controls-with-labels-expected-android-assist-data.txt
index 1b2d646a..fb15562 100644
--- a/content/test/data/accessibility/html/interactive-controls-with-labels-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/interactive-controls-with-labels-expected-android-assist-data.txt
@@ -1,59 +1,59 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="label", id="label1"]
-++++TextView text:"Test label" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"aria label" textSize:16.00 style:0 bundle:[aria-label="aria label", display="block", htmlTag="div"]
-++++TextView text:"Generic container" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"Test label" textSize:16.00 style:0 bundle:[aria-labelledby="label1", display="block", htmlTag="div"]
-++++TextView text:"Generic container with aria-labelledby" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++EditText text:"Textbox" textSize:16.00 style:0 bundle:[aria-label="aria label", display="block", htmlTag="div", role="textbox"]
-++++TextView text:"Textbox" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++EditText text:"Textbox with aria-labelledby" textSize:16.00 style:0 bundle:[aria-labelledby="label1", display="block", htmlTag="div", role="textbox"]
-++++TextView text:"Textbox with aria-labelledby" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++Button text:"aria label" textSize:16.00 style:0 bundle:[aria-label="aria label", display="block", htmlTag="div", role="button"]
-++++TextView text:"Button" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++Button text:"Test label" textSize:16.00 style:0 bundle:[aria-labelledby="label1", display="block", htmlTag="div", role="button"]
-++++TextView text:"Button with aria-labelledby" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++EditText text:"aria label" textSize:13.33 style:0 bundle:[aria-activedescendant="option1", aria-controls="listbox-for-input-1", aria-label="aria label", display="inline-block", htmlTag="input", role="combobox", type="text"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", id="listbox-for-input-1", role="listbox"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", id="option1", role="option"]
-++++++TextView text:"• " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"Option 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", id="option2", role="option"]
-++++++TextView text:"• " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"Option 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++EditText text:"Test label" textSize:13.33 style:0 bundle:[aria-activedescendant="option3", aria-controls="listbox-for-input-2", aria-labelledby="label1", display="inline-block", htmlTag="input", role="combobox", type="text"]
-++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", id="listbox-for-input-2", role="listbox"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", id="option3", role="option"]
-++++++TextView text:"• " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"Option 3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", id="option4", role="option"]
-++++++TextView text:"• " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"Option 4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++Spinner text:"Combobox" textSize:16.00 style:0 bundle:[aria-controls="listbox2", aria-label="aria label", display="block", htmlTag="div", role="combobox", tabindex="0"]
-++++TextView text:"Combobox" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", id="listbox1", role="listbox"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", id="option5", role="option"]
-++++++TextView text:"• " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"Option 5" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", id="option6", role="option"]
-++++++TextView text:"• " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"Option 6" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++Spinner text:"Combobox with aria-labelledby" textSize:16.00 style:0 bundle:[aria-controls="listbox2", aria-labelledby="label1", display="block", htmlTag="div", role="combobox", tabindex="0"]
-++++TextView text:"Combobox with aria-labelledby" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul", id="listbox2", role="listbox"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", id="option7", role="option"]
-++++++TextView text:"• " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"Option 7" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li", id="option8", role="option"]
-++++++TextView text:"• " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"Option 8" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++Spinner text:"aria label" textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-label="aria label", display="inline-flex", htmlTag="input", type="time", value="12:05"]
-++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div", pseudo="-webkit-date-and-time-value"]
-++++++TextView text:"12:05 PM" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++Spinner text:"Test label" textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-labelledby="label1", display="inline-flex", htmlTag="input", type="time", value="12:05"]
-++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div", pseudo="-webkit-date-and-time-value"]
-++++++TextView text:"12:05 PM" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++Spinner text:"#E4E4E4" textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-label="aria label", display="inline-block", htmlTag="input", type="color", value="#e4e4e4"]
-++Spinner text:"#E4E4E4" textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-labelledby="label1", display="inline-block", htmlTag="input", type="color", value="#e4e4e4"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="label"}, {display="inline"}, {id="label1"}]
+++++TextView text:"Test label" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"aria label" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="aria label"}]
+++++TextView text:"Generic container" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"Test label" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-labelledby="label1"}]
+++++TextView text:"Generic container with aria-labelledby" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++EditText text:"Textbox" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="aria label"}, {role="textbox"}]
+++++TextView text:"Textbox" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++EditText text:"Textbox with aria-labelledby" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-labelledby="label1"}, {role="textbox"}]
+++++TextView text:"Textbox with aria-labelledby" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button text:"aria label" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="aria label"}, {role="button"}]
+++++TextView text:"Button" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button text:"Test label" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-labelledby="label1"}, {role="button"}]
+++++TextView text:"Button with aria-labelledby" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++EditText text:"aria label" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-activedescendant="option1"}, {aria-controls="listbox-for-input-1"}, {aria-label="aria label"}, {role="combobox"}, {type="text"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {id="listbox-for-input-1"}, {role="listbox"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {id="option1"}, {role="option"}]
+++++++TextView text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"Option 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {id="option2"}, {role="option"}]
+++++++TextView text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"Option 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++EditText text:"Test label" textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-activedescendant="option3"}, {aria-controls="listbox-for-input-2"}, {aria-labelledby="label1"}, {role="combobox"}, {type="text"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {id="listbox-for-input-2"}, {role="listbox"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {id="option3"}, {role="option"}]
+++++++TextView text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"Option 3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {id="option4"}, {role="option"}]
+++++++TextView text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"Option 4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Spinner text:"Combobox" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-controls="listbox2"}, {aria-label="aria label"}, {role="combobox"}, {tabindex="0"}]
+++++TextView text:"Combobox" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {id="listbox1"}, {role="listbox"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {id="option5"}, {role="option"}]
+++++++TextView text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"Option 5" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {id="option6"}, {role="option"}]
+++++++TextView text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"Option 6" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Spinner text:"Combobox with aria-labelledby" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-controls="listbox2"}, {aria-labelledby="label1"}, {role="combobox"}, {tabindex="0"}]
+++++TextView text:"Combobox with aria-labelledby" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {id="listbox2"}, {role="listbox"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {id="option7"}, {role="option"}]
+++++++TextView text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"Option 7" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {id="option8"}, {role="option"}]
+++++++TextView text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"Option 8" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Spinner text:"aria label" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-flex"}, {aria-label="aria label"}, {type="time"}, {value="12:05"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {pseudo="-webkit-date-and-time-value"}]
+++++++TextView text:"12:05 PM" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Spinner text:"Test label" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-flex"}, {aria-labelledby="label1"}, {type="time"}, {value="12:05"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {pseudo="-webkit-date-and-time-value"}]
+++++++TextView text:"12:05 PM" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Spinner text:"#E4E4E4" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-label="aria label"}, {type="color"}, {value="#e4e4e4"}]
+++Spinner text:"#E4E4E4" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {aria-labelledby="label1"}, {type="color"}, {value="#e4e4e4"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/isInteresting-expected-android-assist-data.txt b/content/test/data/accessibility/html/isInteresting-expected-android-assist-data.txt
index bdff4d0..7256db3 100644
--- a/content/test/data/accessibility/html/isInteresting-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/isInteresting-expected-android-assist-data.txt
@@ -1,8 +1,8 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:32.00 style:1 bundle:[display="block", htmlTag="h1"]
-++++TextView text:"A non focusable child of a control should not be interesting on Android" textSize:32.00 style:1 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", onclick="alert('success');"]
-++++TextView text:"Div with click handler" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++Button text:"I am interesting" textSize:16.00 style:0 bundle:[aria-label="I am interesting", display="block", htmlTag="div", onclick="alert('success');", role="button"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++TextView text:"I should not be interesting" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:32.0 style:1 htmlInfo:[{htmlTag="h1"}, {display="block"}]
+++++TextView text:"A non focusable child of a control should not be interesting on Android" textSize:32.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {onclick="alert('success');"}]
+++++TextView text:"Div with click handler" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++Button text:"I am interesting" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="I am interesting"}, {onclick="alert('success');"}, {role="button"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++TextView text:"I should not be interesting" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/label-expected-android-assist-data.txt b/content/test/data/accessibility/html/label-expected-android-assist-data.txt
index 8f194004..7e2f0fd 100644
--- a/content/test/data/accessibility/html/label-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/label-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="label"]
-++++++TextView text:"Label" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="label"}, {display="inline"}]
+++++++TextView text:"Label" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/legend-expected-android-assist-data.txt b/content/test/data/accessibility/html/legend-expected-android-assist-data.txt
index 8d4b96150..0fa3a07 100644
--- a/content/test/data/accessibility/html/legend-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/legend-expected-android-assist-data.txt
@@ -1,11 +1,11 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="form"]
-++++View text:"Browser Engines:" textSize:16.00 style:0 bundle:[display="block", htmlTag="fieldset"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="legend"]
-++++++++TextView text:"Browser Engines:" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"Browser: " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++EditText textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", type="text"]
-++++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++++TextView text:" Rendering Engine: " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++EditText textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", type="text"]
-++++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="form"}, {display="block"}]
+++++View text:"Browser Engines:" textSize:16.0 style:0 htmlInfo:[{htmlTag="fieldset"}, {display="block"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="legend"}, {display="block"}]
+++++++++TextView text:"Browser Engines:" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"Browser: " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="text"}]
+++++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++++TextView text:" Rendering Engine: " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="text"}]
+++++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/li-expected-android-assist-data.txt b/content/test/data/accessibility/html/li-expected-android-assist-data.txt
index 2c7f863..4829b48 100644
--- a/content/test/data/accessibility/html/li-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/li-expected-android-assist-data.txt
@@ -1,11 +1,11 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul"]
-++++View text:"Custom name" textSize:16.00 style:0 bundle:[aria-label="Custom name", display="list-item", htmlTag="li"]
-++++++View text:"• " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"Item 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"• " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"Item 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"• " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"Item 3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}]
+++++View text:"Custom name" textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-label="Custom name"}]
+++++++View text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"Item 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"Item 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"Item 3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/link-inside-heading-expected-android-assist-data.txt b/content/test/data/accessibility/html/link-inside-heading-expected-android-assist-data.txt
index 300ae7f..477cc8d 100644
--- a/content/test/data/accessibility/html/link-inside-heading-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/link-inside-heading-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:32.00 style:1 bundle:[display="block", htmlTag="h1"]
-++++View textSize:32.00 style:5 fgColor:-16776978 bundle:[display="inline", href="#", htmlTag="a"]
-++++++TextView text:"Link In Heading" textSize:32.00 style:5 fgColor:-16776978 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:32.0 style:1 htmlInfo:[{htmlTag="h1"}, {display="block"}]
+++++View textSize:32.0 style:5 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#"}]
+++++++TextView text:"Link In Heading" textSize:32.0 style:5 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/list-expected-android-assist-data.txt b/content/test/data/accessibility/html/list-expected-android-assist-data.txt
index 9fea8f5752..4e7e041 100644
--- a/content/test/data/accessibility/html/list-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/list-expected-android-assist-data.txt
@@ -1,20 +1,20 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"• " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"tic" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"• " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"tac" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"• " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"toe" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ListView textSize:16.00 style:0 bundle:[class="inlineList", display="block", htmlTag="ul"]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="li"]
-++++++TextView text:"tic" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="li"]
-++++++TextView text:"tac" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="li"]
-++++++TextView text:"toe" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"tic" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"tac" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"toe" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}, {class="inlineList"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="inline"}]
+++++++TextView text:"tic" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="inline"}]
+++++++TextView text:"tac" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="inline"}]
+++++++TextView text:"toe" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/list-item-aria-setsize-unknown-expected-android-assist-data.txt b/content/test/data/accessibility/html/list-item-aria-setsize-unknown-expected-android-assist-data.txt
index fc842a23..31ee95a 100644
--- a/content/test/data/accessibility/html/list-item-aria-setsize-unknown-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/list-item-aria-setsize-unknown-expected-android-assist-data.txt
@@ -1,15 +1,15 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul"]
-++++View textSize:16.00 style:0 bundle:[aria-posinset="5", aria-setsize="-1", display="list-item", htmlTag="li"]
-++++++TextView text:"Level 1, item 5 of set size unknown" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-posinset="6", aria-setsize="-1", display="list-item", htmlTag="li"]
-++++++TextView text:"Level 1, item 6 of set size unknown" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul"]
-++++++++View textSize:16.00 style:0 bundle:[aria-posinset="6", aria-setsize="-1", display="list-item", htmlTag="li"]
-++++++++++TextView text:"Level 2, item 6 of set size unknown" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[aria-posinset="7", aria-setsize="-1", display="list-item", htmlTag="li"]
-++++++++++TextView text:"Level 2, item 7 of set size unknown" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-posinset="7", aria-setsize="2", display="list-item", htmlTag="li"]
-++++++TextView text:"Level 1, item 7 of set size 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[aria-posinset="8", aria-setsize="3", display="list-item", htmlTag="li"]
-++++++TextView text:"Level 1, item 8 of set size 3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-posinset="5"}, {aria-setsize="-1"}]
+++++++TextView text:"Level 1, item 5 of set size unknown" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-posinset="6"}, {aria-setsize="-1"}]
+++++++TextView text:"Level 1, item 6 of set size unknown" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-posinset="6"}, {aria-setsize="-1"}]
+++++++++++TextView text:"Level 2, item 6 of set size unknown" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-posinset="7"}, {aria-setsize="-1"}]
+++++++++++TextView text:"Level 2, item 7 of set size unknown" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-posinset="7"}, {aria-setsize="2"}]
+++++++TextView text:"Level 1, item 7 of set size 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-posinset="8"}, {aria-setsize="3"}]
+++++++TextView text:"Level 1, item 8 of set size 3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/list-item-aria-setsize-unknown-flattened-expected-android-assist-data.txt b/content/test/data/accessibility/html/list-item-aria-setsize-unknown-flattened-expected-android-assist-data.txt
index 6da6c66..fad818d 100644
--- a/content/test/data/accessibility/html/list-item-aria-setsize-unknown-flattened-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/list-item-aria-setsize-unknown-flattened-expected-android-assist-data.txt
@@ -1,32 +1,32 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ol", role="list", start="1"]
-++++View textSize:16.00 style:0 bundle:[aria-level="1", aria-posinset="1", aria-setsize="-1", display="list-item", htmlTag="li", role="listitem"]
-++++++TextView text:"Level 1, item 1 of set size unknown" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ol", role="list", start="1"]
-++++View textSize:16.00 style:0 bundle:[aria-level="2", aria-posinset="1", aria-setsize="-1", display="list-item", htmlTag="li", role="listitem"]
-++++++TextView text:"++Level 2, item 1 of set size unknown" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ol", role="list", start="2"]
-++++View textSize:16.00 style:0 bundle:[aria-level="2", aria-posinset="2", aria-setsize="-1", display="list-item", htmlTag="li", role="listitem"]
-++++++TextView text:"++Level 2, item 2 of set size unknown" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ol", role="list", start="3"]
-++++View textSize:16.00 style:0 bundle:[aria-level="2", aria-posinset="3", aria-setsize="-1", display="list-item", htmlTag="li", role="listitem"]
-++++++TextView text:"++Level 2, item 3 of set size unknown" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ol", role="list", start="1"]
-++++View textSize:16.00 style:0 bundle:[aria-level="3", aria-posinset="1", aria-setsize="-1", display="list-item", htmlTag="li", role="listitem"]
-++++++TextView text:"++++Level 3, item 1 of set size unknown" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ol", role="list", start="2"]
-++++View textSize:16.00 style:0 bundle:[aria-level="3", aria-posinset="2", aria-setsize="-1", display="list-item", htmlTag="li", role="listitem"]
-++++++TextView text:"++++Level 3, item 2 of set size unknown" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ol", role="list", start="2"]
-++++View textSize:16.00 style:0 bundle:[aria-level="1", aria-posinset="2", aria-setsize="-1", display="list-item", htmlTag="li", role="listitem"]
-++++++TextView text:"Level 1, item 2 of set size unknown" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ol", role="list", start="3"]
-++++View textSize:16.00 style:0 bundle:[aria-level="1", aria-posinset="3", aria-setsize="-1", display="list-item", htmlTag="li", role="listitem"]
-++++++TextView text:"Level 1, item 3 of set size unknown" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="list"]
-++++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ol", role="list", start="4"]
-++++++View textSize:16.00 style:0 bundle:[aria-posinset="4", display="list-item", htmlTag="li", role="listitem"]
-++++++++TextView text:"Level Unspecified, aria-setsize attribute does not exist, item 4 of set size 4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ol", role="list", start="5"]
-++++++View textSize:16.00 style:0 bundle:[aria-posinset="5", display="list-item", htmlTag="li", role="listitem"]
-++++++++TextView text:"Level Unspecified, aria-setsize attribute does not exist, item 5 of set size 5" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ol"}, {display="block"}, {role="list"}, {start="1"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-level="1"}, {aria-posinset="1"}, {aria-setsize="-1"}, {role="listitem"}]
+++++++TextView text:"Level 1, item 1 of set size unknown" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ol"}, {display="block"}, {role="list"}, {start="1"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-level="2"}, {aria-posinset="1"}, {aria-setsize="-1"}, {role="listitem"}]
+++++++TextView text:"++Level 2, item 1 of set size unknown" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ol"}, {display="block"}, {role="list"}, {start="2"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-level="2"}, {aria-posinset="2"}, {aria-setsize="-1"}, {role="listitem"}]
+++++++TextView text:"++Level 2, item 2 of set size unknown" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ol"}, {display="block"}, {role="list"}, {start="3"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-level="2"}, {aria-posinset="3"}, {aria-setsize="-1"}, {role="listitem"}]
+++++++TextView text:"++Level 2, item 3 of set size unknown" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ol"}, {display="block"}, {role="list"}, {start="1"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-level="3"}, {aria-posinset="1"}, {aria-setsize="-1"}, {role="listitem"}]
+++++++TextView text:"++++Level 3, item 1 of set size unknown" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ol"}, {display="block"}, {role="list"}, {start="2"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-level="3"}, {aria-posinset="2"}, {aria-setsize="-1"}, {role="listitem"}]
+++++++TextView text:"++++Level 3, item 2 of set size unknown" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ol"}, {display="block"}, {role="list"}, {start="2"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-level="1"}, {aria-posinset="2"}, {aria-setsize="-1"}, {role="listitem"}]
+++++++TextView text:"Level 1, item 2 of set size unknown" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ol"}, {display="block"}, {role="list"}, {start="3"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-level="1"}, {aria-posinset="3"}, {aria-setsize="-1"}, {role="listitem"}]
+++++++TextView text:"Level 1, item 3 of set size unknown" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="list"}]
+++++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ol"}, {display="block"}, {role="list"}, {start="4"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-posinset="4"}, {role="listitem"}]
+++++++++TextView text:"Level Unspecified, aria-setsize attribute does not exist, item 4 of set size 4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ol"}, {display="block"}, {role="list"}, {start="5"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}, {aria-posinset="5"}, {role="listitem"}]
+++++++++TextView text:"Level Unspecified, aria-setsize attribute does not exist, item 5 of set size 5" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/list-markers-expected-android-assist-data.txt b/content/test/data/accessibility/html/list-markers-expected-android-assist-data.txt
index a3477e6..a6ae445ab 100644
--- a/content/test/data/accessibility/html/list-markers-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/list-markers-expected-android-assist-data.txt
@@ -1,17 +1,17 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"• " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"First item properly groups itself despite " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"bolded" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++++TextView text:" text." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"• " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"This should also be " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"seen" textSize:16.00 style:2 bundle:[display="", htmlTag=""]
-++++++TextView text:" as a group." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"• " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"Some " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++TextView text:"more" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++++TextView text:" text." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"First item properly groups itself despite " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"bolded" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:" text." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"This should also be " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"seen" textSize:16.0 style:2 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:" as a group." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"Some " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:"more" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:" text." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/main-expected-android-assist-data.txt b/content/test/data/accessibility/html/main-expected-android-assist-data.txt
index d20f3d8..de17556 100644
--- a/content/test/data/accessibility/html/main-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/main-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="main"]
-++++TextView text:"This is main element." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", role="main"]
-++++TextView text:"This is an ARIA role main." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="main"}, {display="block"}]
+++++TextView text:"This is main element." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="main"}]
+++++TextView text:"This is an ARIA role main." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/map-any-contents-expected-android-assist-data.txt b/content/test/data/accessibility/html/map-any-contents-expected-android-assist-data.txt
index 9cf82c4..c8fbe26 100644
--- a/content/test/data/accessibility/html/map-any-contents-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/map-any-contents-expected-android-assist-data.txt
@@ -1,13 +1,13 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Image text:"pipe" textSize:16.00 style:0 bundle:[alt="pipe", display="inline", height="126", htmlTag="img", src="pipe.jpg", usemap="#pipe", width="145"]
-++++++View textSize:32.00 style:1 bundle:[display="block", htmlTag="h1"]
-++++++++TextView text:"Headings are allowed in a map" textSize:32.00 style:1 bundle:[display="", htmlTag=""]
-++++++View text:"pipe1" textSize:0.00 style:0 fgColor:0 bundle:[alt="pipe1", coords="0,0,145,126", display="inline", href="fake.htm", htmlTag="area", shape="rect"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"So are " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bgColor:-256 bundle:[display="inline", htmlTag="mark"]
-++++++++++TextView text:"other elements" textSize:16.00 style:0 bgColor:-256 bundle:[display="", htmlTag=""]
-++++++++TextView text:"!" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++Button textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="button"]
-++++++++TextView text:"Even a button" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Image text:"pipe" textSize:16.0 style:0 htmlInfo:[{htmlTag="img"}, {display="inline"}, {alt="pipe"}, {height="126"}, {src="pipe.jpg"}, {usemap="#pipe"}, {width="145"}]
+++++++View textSize:32.0 style:1 htmlInfo:[{htmlTag="h1"}, {display="block"}]
+++++++++TextView text:"Headings are allowed in a map" textSize:32.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View text:"pipe1" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="area"}, {display="inline"}, {alt="pipe1"}, {coords="0,0,145,126"}, {href="fake.htm"}, {shape="rect"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"So are " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 bgColor:-256 htmlInfo:[{htmlTag="mark"}, {display="inline"}]
+++++++++++TextView text:"other elements" textSize:16.0 style:0 bgColor:-256 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++TextView text:"!" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++Button textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}]
+++++++++TextView text:"Even a button" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/mark-expected-android-assist-data.txt b/content/test/data/accessibility/html/mark-expected-android-assist-data.txt
index 435b780..0a2fcae5 100644
--- a/content/test/data/accessibility/html/mark-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/mark-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"This test is to check " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bgColor:-256 bundle:[display="inline", htmlTag="mark"]
-++++++TextView text:"mark tag" textSize:16.00 style:0 bgColor:-256 bundle:[display="", htmlTag=""]
-++++TextView text:"." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"This test is to check " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 bgColor:-256 htmlInfo:[{htmlTag="mark"}, {display="inline"}]
+++++++TextView text:"mark tag" textSize:16.0 style:0 bgColor:-256 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/math-expected-android-assist-data.txt b/content/test/data/accessibility/html/math-expected-android-assist-data.txt
index cccec79..792c764e 100644
--- a/content/test/data/accessibility/html/math-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/math-expected-android-assist-data.txt
@@ -1,16 +1,16 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++View textSize:16.00 style:0 bundle:[display="math", htmlTag="math", xmlns="http://www.w3.org/1998/Math/MathML"]
-++++++View textSize:16.00 style:0 bundle:[display="block math", htmlTag="mrow"]
-++++++++View textSize:16.00 style:0 bundle:[display="block math", htmlTag="msup"]
-++++++++++View textSize:16.00 style:0 bundle:[display="block math", htmlTag="mi"]
-++++++++++++TextView text:"𝐴" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++++View textSize:11.36 style:0 bundle:[display="block math", htmlTag="mn"]
-++++++++++++TextView text:"2" textSize:11.36 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[display="block math", htmlTag="mo"]
-++++++++++TextView text:"+" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[display="block math", htmlTag="msup"]
-++++++++++View textSize:16.00 style:0 bundle:[display="block math", htmlTag="mi"]
-++++++++++++TextView text:"𝐵" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++++View textSize:11.36 style:0 bundle:[display="block math", htmlTag="mn"]
-++++++++++++TextView text:"2" textSize:11.36 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="math"}, {display="math"}, {xmlns="http://www.w3.org/1998/Math/MathML"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="mrow"}, {display="block math"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="msup"}, {display="block math"}]
+++++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="mi"}, {display="block math"}]
+++++++++++++TextView text:"𝐴" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++++View textSize:11.4 style:0 htmlInfo:[{htmlTag="mn"}, {display="block math"}]
+++++++++++++TextView text:"2" textSize:11.4 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="mo"}, {display="block math"}]
+++++++++++TextView text:"+" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="msup"}, {display="block math"}]
+++++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="mi"}, {display="block math"}]
+++++++++++++TextView text:"𝐵" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++++View textSize:11.4 style:0 htmlInfo:[{htmlTag="mn"}, {display="block math"}]
+++++++++++++TextView text:"2" textSize:11.4 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/menu-expected-android-assist-data.txt b/content/test/data/accessibility/html/menu-expected-android-assist-data.txt
index 1fb3fd2..c0e7ae7 100644
--- a/content/test/data/accessibility/html/menu-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/menu-expected-android-assist-data.txt
@@ -1,8 +1,8 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"Menu is deprecated, but it may still be used semantically with list item children. For more history, see crbug.com/87553." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="menu"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++TextView text:"Cats" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++TextView text:"Dogs" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"Menu is deprecated, but it may still be used semantically with list item children. For more history, see crbug.com/87553." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="menu"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++TextView text:"Cats" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++TextView text:"Dogs" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/meter-expected-android-assist-data.txt b/content/test/data/accessibility/html/meter-expected-android-assist-data.txt
index 2587521..5f0c079 100644
--- a/content/test/data/accessibility/html/meter-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/meter-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++ProgressBar textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="meter", max="10", min="1", value="2"]
-++++++View textSize:16.00 style:0 bundle:[display="grid", htmlTag="div", pseudo="-webkit-meter-inner-element"]
-++++++++View textSize:16.00 style:0 bgColor:-1052689 bundle:[display="block", htmlTag="div", pseudo="-webkit-meter-bar"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++ProgressBar textSize:16.0 style:0 htmlInfo:[{htmlTag="meter"}, {display="inline-block"}, {max="10"}, {min="1"}, {value="2"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="grid"}, {pseudo="-webkit-meter-inner-element"}]
+++++++++View textSize:16.0 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="div"}, {display="block"}, {pseudo="-webkit-meter-bar"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/navigation-expected-android-assist-data.txt b/content/test/data/accessibility/html/navigation-expected-android-assist-data.txt
index ccdc8e9..1afa344e 100644
--- a/content/test/data/accessibility/html/navigation-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/navigation-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="nav"]
-++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="/fake/", htmlTag="a"]
-++++++TextView text:"Don't click on me" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="nav"}, {display="block"}]
+++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="/fake/"}]
+++++++TextView text:"Don't click on me" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/nestedlist-expected-android-assist-data.txt b/content/test/data/accessibility/html/nestedlist-expected-android-assist-data.txt
index e73b86b6..10ebf57 100644
--- a/content/test/data/accessibility/html/nestedlist-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/nestedlist-expected-android-assist-data.txt
@@ -1,31 +1,31 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"This is a multi-leveled list" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ol"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"1. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"Sports" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ol"]
-++++++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++++++View text:"1. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++++++TextView text:"Tennis" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++++++View text:"2. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++++++TextView text:"basketball" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"2. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"Books" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ol"]
-++++++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++++++View text:"1. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++++++TextView text:"Oliver Twist" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++++++View text:"2. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++++++TextView text:"Kindred" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++++++View text:"3. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++++++TextView text:"The Promise of Sleep" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"3. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"Recipes" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ol"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"This is a multi-leveled list" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ol"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"1. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"Sports" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ol"}, {display="block"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++++++View text:"1. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++++++TextView text:"Tennis" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++++++View text:"2. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++++++TextView text:"basketball" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"2. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"Books" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ol"}, {display="block"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++++++View text:"1. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++++++TextView text:"Oliver Twist" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++++++View text:"2. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++++++TextView text:"Kindred" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++++++View text:"3. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++++++TextView text:"The Promise of Sleep" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"3. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"Recipes" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ol"}, {display="block"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/object-expected-android-assist-data.txt b/content/test/data/accessibility/html/object-expected-android-assist-data.txt
index 3499b2a..9c20f7a 100644
--- a/content/test/data/accessibility/html/object-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/object-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++View textSize:16.00 style:0 bundle:[data="../../../../media/test/data/bear.swf", display="inline", height="400", htmlTag="object", width="400"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="object"}, {display="inline"}, {data="../../../../media/test/data/bear.swf"}, {height="400"}, {width="400"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/offscreen-iframe-content-expected-android-assist-data.txt b/content/test/data/accessibility/html/offscreen-iframe-content-expected-android-assist-data.txt
index 4bb58c8..d0c1475 100644
--- a/content/test/data/accessibility/html/offscreen-iframe-content-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/offscreen-iframe-content-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View text:"iframe_onscreen" textSize:16.00 style:0 bgColor:-65536 bundle:[aria-label="iframe_onscreen", display="block", htmlTag="div", role="group", style="height:300px; background-color: red;"]
-++View text:"iframe_offscreen" textSize:16.00 style:0 bgColor:-16744448 bundle:[aria-label="iframe_offscreen", display="block", htmlTag="div", role="group", style="height:200px; background-color: green"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View text:"iframe_onscreen" textSize:16.0 style:0 bgColor:-65536 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="iframe_onscreen"}, {role="group"}, {style="height:300px; background-color: red;"}]
+++View text:"iframe_offscreen" textSize:16.0 style:0 bgColor:-16744448 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="iframe_offscreen"}, {role="group"}, {style="height:200px; background-color: green"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/offscreen-iframe-expected-android-assist-data.txt b/content/test/data/accessibility/html/offscreen-iframe-expected-android-assist-data.txt
index 5af87ed5..43b53298 100644
--- a/content/test/data/accessibility/html/offscreen-iframe-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/offscreen-iframe-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++View textSize:16.00 style:0 bundle:[display="inline", height="300px", htmlTag="iframe", src="offscreen-iframe-content.html", width="200px"]
-++++++View textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++++++++View text:"iframe_onscreen" textSize:16.00 style:0 bgColor:-65536 bundle:[aria-label="iframe_onscreen", display="block", htmlTag="div", role="group", style="height:300px; background-color: red;"]
-++++++++View text:"iframe_offscreen" textSize:16.00 style:0 bgColor:-16744448 bundle:[aria-label="iframe_offscreen", display="block", htmlTag="div", role="group", style="height:200px; background-color: green"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="iframe"}, {display="inline"}, {height="300px"}, {src="offscreen-iframe-content.html"}, {width="200px"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++++++++View text:"iframe_onscreen" textSize:16.0 style:0 bgColor:-65536 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="iframe_onscreen"}, {role="group"}, {style="height:300px; background-color: red;"}]
+++++++++View text:"iframe_offscreen" textSize:16.0 style:0 bgColor:-16744448 htmlInfo:[{htmlTag="div"}, {display="block"}, {aria-label="iframe_offscreen"}, {role="group"}, {style="height:200px; background-color: green"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/offscreen-select-expected-android-assist-data.txt b/content/test/data/accessibility/html/offscreen-select-expected-android-assist-data.txt
index ac9d7fdd..e1461a2 100644
--- a/content/test/data/accessibility/html/offscreen-select-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/offscreen-select-expected-android-assist-data.txt
@@ -1,11 +1,11 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View text:"Onscreen 1" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="select", name="Select onscreen"]
-++++View textSize:0.00 style:0 fgColor:0 bundle:[display="", htmlTag=""]
-++++++View text:"Onscreen 1" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="1"]
-++++++View text:"Onscreen 2" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="2"]
-++++++View text:"Onscreen 3" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="3"]
-++View text:"Offscreen 1" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="select", name="Select offscreen"]
-++++View textSize:0.00 style:0 fgColor:0 bundle:[display="", htmlTag=""]
-++++++View text:"Offscreen 1" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="1"]
-++++++View text:"Offscreen 2" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="2"]
-++++++View text:"Offscreen 3" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="3"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View text:"Onscreen 1" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="select"}, {display="inline-block"}, {name="Select onscreen"}]
+++++View textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View text:"Onscreen 1" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="1"}]
+++++++View text:"Onscreen 2" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="2"}]
+++++++View text:"Onscreen 3" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="3"}]
+++View text:"Offscreen 1" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="select"}, {display="inline-block"}, {name="Select offscreen"}]
+++++View textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View text:"Offscreen 1" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="1"}]
+++++++View text:"Offscreen 2" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="2"}]
+++++++View text:"Offscreen 3" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="3"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/ol-expected-android-assist-data.txt b/content/test/data/accessibility/html/ol-expected-android-assist-data.txt
index cb6c57d8..f9de2ec 100644
--- a/content/test/data/accessibility/html/ol-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/ol-expected-android-assist-data.txt
@@ -1,21 +1,21 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ol"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"1. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"Chrome" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"2. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"Safari" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"3. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"IE" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ol", start="10"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"10. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"Android" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"11. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"Mac" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"12. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"Windows" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ol"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"1. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"Chrome" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"2. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"Safari" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"3. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"IE" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ol"}, {display="block"}, {start="10"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"10. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"Android" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"11. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"Mac" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"12. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"Windows" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/optgroup-expected-android-assist-data.txt b/content/test/data/accessibility/html/optgroup-expected-android-assist-data.txt
index 4d0b97a..c3104b2 100644
--- a/content/test/data/accessibility/html/optgroup-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/optgroup-expected-android-assist-data.txt
@@ -1,12 +1,12 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++View textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="select", id="listbox", size="10"]
-++++++View textSize:0.00 style:0 fgColor:0 bundle:[display="", htmlTag=""]
-++++++++View text:"One" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", id="listbox_option_enabled_one", value="listbox_e1"]
-++++++++View text:"Two" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="listbox_e2"]
-++++++++View text:"Three" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="listbox_e3"]
-++++++++View text:"Four" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="listbox_e4"]
-++++++++View text:"One" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", id="listbox_option_disabled_one", value="listbox_d1"]
-++++++++View text:"Two" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="listbox_d2"]
-++++++++View text:"Three" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="listbox_d3"]
-++++++++View text:"Four" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="listbox_d4"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++View textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="select"}, {display="inline-block"}, {id="listbox"}, {size="10"}]
+++++++View textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View text:"One" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {id="listbox_option_enabled_one"}, {value="listbox_e1"}]
+++++++++View text:"Two" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="listbox_e2"}]
+++++++++View text:"Three" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="listbox_e3"}]
+++++++++View text:"Four" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="listbox_e4"}]
+++++++++View text:"One" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {id="listbox_option_disabled_one"}, {value="listbox_d1"}]
+++++++++View text:"Two" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="listbox_d2"}]
+++++++++View text:"Three" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="listbox_d3"}]
+++++++++View text:"Four" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="listbox_d4"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/output-expected-android-assist-data.txt b/content/test/data/accessibility/html/output-expected-android-assist-data.txt
index 2e879763..ff3d22f 100644
--- a/content/test/data/accessibility/html/output-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/output-expected-android-assist-data.txt
@@ -1,9 +1,9 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="form", oninput="o.value = (a.valueAsNumber || 0) + (b.valueAsNumber || 0)", onsubmit="return false"]
-++++EditText textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", name="a", step="any", type="number"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++TextView text:" + " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++EditText textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", name="b", step="any", type="number"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
-++++TextView text:" =" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", for="a b", htmlTag="output", name="o"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="form"}, {display="block"}, {oninput="o.value = (a.valueAsNumber || 0) + (b.valueAsNumber || 0)"}, {onsubmit="return false"}]
+++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {name="a"}, {step="any"}, {type="number"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++TextView text:" + " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {name="b"}, {step="any"}, {type="number"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
+++++TextView text:" =" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="output"}, {display="inline"}, {for="a b"}, {name="o"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/overflow-actions-expected-android-assist-data.txt b/content/test/data/accessibility/html/overflow-actions-expected-android-assist-data.txt
index 78a93235..0d2fdca 100644
--- a/content/test/data/accessibility/html/overflow-actions-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/overflow-actions-expected-android-assist-data.txt
@@ -1,11 +1,11 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", style="overflow:scroll; width: 200px; height: 50px"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++TextView text:"Example Paragraph 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++TextView text:"Example Paragraph 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", style="overflow:hidden; width: 200px; height: 50px"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++TextView text:"Example Paragraph 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++TextView text:"Example Paragraph 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="overflow:scroll; width: 200px; height: 50px"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++TextView text:"Example Paragraph 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++TextView text:"Example Paragraph 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="overflow:hidden; width: 200px; height: 50px"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++TextView text:"Example Paragraph 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++TextView text:"Example Paragraph 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/p-expected-android-assist-data.txt b/content/test/data/accessibility/html/p-expected-android-assist-data.txt
index a8903d6..57a1362 100644
--- a/content/test/data/accessibility/html/p-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/p-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++TextView text:"Before" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"Paragraph" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++TextView text:"After" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++TextView text:"Before" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"Paragraph" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++TextView text:"After" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/param-expected-android-assist-data.txt b/content/test/data/accessibility/html/param-expected-android-assist-data.txt
index 3499b2a..9c20f7a 100644
--- a/content/test/data/accessibility/html/param-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/param-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++View textSize:16.00 style:0 bundle:[data="../../../../media/test/data/bear.swf", display="inline", height="400", htmlTag="object", width="400"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="object"}, {display="inline"}, {data="../../../../media/test/data/bear.swf"}, {height="400"}, {width="400"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/picture-expected-android-assist-data.txt b/content/test/data/accessibility/html/picture-expected-android-assist-data.txt
index ffcd2678c..4a17e3bf 100644
--- a/content/test/data/accessibility/html/picture-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/picture-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Image text:"x" textSize:16.00 style:0 bundle:[alt="x", display="inline", height="200", htmlTag="img", sizes="100vw", src="./200.jpg", srcset="./200.jpg 200w,./400.jpg 400w", width="200"]
-++++Image text:"  " textSize:16.00 style:0 bundle:[alt=" ", display="inline", height="200", htmlTag="img", sizes="100vw", src="./200.jpg", srcset="./200.jpg 200w,./400.jpg 400w", width="200"]
-++++Image text:"400" textSize:16.00 style:0 bundle:[display="inline", height="200", htmlTag="img", sizes="100vw", src="./200.jpg", srcset="./200.jpg 200w,./400.jpg 400w", width="200"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Image text:"x" textSize:16.0 style:0 htmlInfo:[{htmlTag="img"}, {display="inline"}, {alt="x"}, {height="200"}, {sizes="100vw"}, {src="./200.jpg"}, {srcset="./200.jpg 200w,./400.jpg 400w"}, {width="200"}]
+++++Image text:"  " textSize:16.0 style:0 htmlInfo:[{htmlTag="img"}, {display="inline"}, {alt=" "}, {height="200"}, {sizes="100vw"}, {src="./200.jpg"}, {srcset="./200.jpg 200w,./400.jpg 400w"}, {width="200"}]
+++++Image text:"400" textSize:16.0 style:0 htmlInfo:[{htmlTag="img"}, {display="inline"}, {height="200"}, {sizes="100vw"}, {src="./200.jpg"}, {srcset="./200.jpg 200w,./400.jpg 400w"}, {width="200"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/pre-expected-android-assist-data.txt b/content/test/data/accessibility/html/pre-expected-android-assist-data.txt
index 0e7ca29..32f0dee 100644
--- a/content/test/data/accessibility/html/pre-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/pre-expected-android-assist-data.txt
@@ -1,9 +1,9 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:13.00 style:0 bundle:[display="block", htmlTag="pre", id="pre"]
-++++TextView text:"This test is to check   pre\nformatting." textSize:13.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="div-pre", style="white-space:pre"]
-++++TextView text:"This test is to check   pre\nformatting" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="div-pre-wrap", style="white-space:pre-wrap"]
-++++TextView text:"This test is to check   pre\nformatting." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", id="div-normal"]
-++++TextView text:"This test is to check pre formatting." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:13.0 style:0 htmlInfo:[{htmlTag="pre"}, {display="block"}, {id="pre"}]
+++++TextView text:"This test is to check   pre\nformatting." textSize:13.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="div-pre"}, {style="white-space:pre"}]
+++++TextView text:"This test is to check   pre\nformatting" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="div-pre-wrap"}, {style="white-space:pre-wrap"}]
+++++TextView text:"This test is to check   pre\nformatting." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {id="div-normal"}]
+++++TextView text:"This test is to check pre formatting." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/progress-expected-android-assist-data.txt b/content/test/data/accessibility/html/progress-expected-android-assist-data.txt
index 0d2be90..dbe0271f 100644
--- a/content/test/data/accessibility/html/progress-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/progress-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++ProgressBar textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="progress", max="100", value="22"]
-++++ProgressBar textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="progress"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++ProgressBar textSize:16.0 style:0 htmlInfo:[{htmlTag="progress"}, {display="inline-block"}, {max="100"}, {value="22"}]
+++++ProgressBar textSize:16.0 style:0 htmlInfo:[{htmlTag="progress"}, {display="inline-block"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/q-expected-android-assist-data.txt b/content/test/data/accessibility/html/q-expected-android-assist-data.txt
index 9ea0539..e6252cac 100644
--- a/content/test/data/accessibility/html/q-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/q-expected-android-assist-data.txt
@@ -1,7 +1,7 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"This is " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"“" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"Chromium Blink" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"”" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" based browser." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"This is " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"“" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"Chromium Blink" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"”" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" based browser." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/replaced-node-across-trees-expected-android-assist-data.txt b/content/test/data/accessibility/html/replaced-node-across-trees-expected-android-assist-data.txt
index c10453b..540913d 100644
--- a/content/test/data/accessibility/html/replaced-node-across-trees-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/replaced-node-across-trees-expected-android-assist-data.txt
@@ -1,11 +1,11 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="s1"]
-++++TextView text:"Before frame" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++View textSize:16.00 style:0 bundle:[aria-label="Cross-process iframe", display="inline", htmlTag="iframe", src="frame/static_text_2.html"]
-++++++View textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="s1"]
-++++++++++++TextView text:"Text in iframe" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="s2"]
-++++TextView text:"After frame" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="s1"}]
+++++TextView text:"Before frame" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="iframe"}, {display="inline"}, {aria-label="Cross-process iframe"}, {src="frame/static_text_2.html"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="s1"}]
+++++++++++++TextView text:"Text in iframe" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="s2"}]
+++++TextView text:"After frame" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/ruby-expected-android-assist-data.txt b/content/test/data/accessibility/html/ruby-expected-android-assist-data.txt
index 58900ac..608659d 100644
--- a/content/test/data/accessibility/html/ruby-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/ruby-expected-android-assist-data.txt
@@ -1,10 +1,10 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View text:"ruby text" textSize:16.00 style:0 bundle:[display="ruby", htmlTag="ruby"]
-++++TextView text:"ruby base" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++View text:"ruby text" textSize:16.00 style:0 bundle:[display="ruby", htmlTag="ruby"]
-++++++TextView text:"ruby base" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"Hi! " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View text:"ruby text" textSize:16.00 style:0 bundle:[display="ruby", htmlTag="ruby"]
-++++++TextView text:"ruby base" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View text:"ruby text" textSize:16.0 style:0 htmlInfo:[{htmlTag="ruby"}, {display="ruby"}]
+++++TextView text:"ruby base" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++View text:"ruby text" textSize:16.0 style:0 htmlInfo:[{htmlTag="ruby"}, {display="ruby"}]
+++++++TextView text:"ruby base" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"Hi! " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View text:"ruby text" textSize:16.0 style:0 htmlInfo:[{htmlTag="ruby"}, {display="ruby"}]
+++++++TextView text:"ruby base" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/s-expected-android-assist-data.txt b/content/test/data/accessibility/html/s-expected-android-assist-data.txt
index 370f7ed..bd1c679 100644
--- a/content/test/data/accessibility/html/s-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/s-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++View textSize:16.00 style:8 bundle:[display="inline", htmlTag="s"]
-++++++TextView text:"My car is blue." textSize:16.00 style:8 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++View textSize:16.0 style:8 htmlInfo:[{htmlTag="s"}, {display="inline"}]
+++++++TextView text:"My car is blue." textSize:16.0 style:8 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/samp-expected-android-assist-data.txt b/content/test/data/accessibility/html/samp-expected-android-assist-data.txt
index 874f72f..e7bf877 100644
--- a/content/test/data/accessibility/html/samp-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/samp-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++TextView text:"Sample output from a computer program" textSize:13.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++TextView text:"Sample output from a computer program" textSize:13.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/scrollable-expected-android-assist-data.txt b/content/test/data/accessibility/html/scrollable-expected-android-assist-data.txt
index 2e98d8a..41155632 100644
--- a/content/test/data/accessibility/html/scrollable-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/scrollable-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[class="not", display="block", htmlTag="div"]
-++++TextView text:"not scrollable" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[class="x", display="block", htmlTag="div", style="width:100px; overflow:auto"]
-++View textSize:16.00 style:0 bundle:[class="y", display="block", htmlTag="div", style="height:100px; overflow:auto"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {class="not"}]
+++++TextView text:"not scrollable" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="width:100px; overflow:auto"}, {class="x"}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="height:100px; overflow:auto"}, {class="y"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/scrollable-overflow-expected-android-assist-data.txt b/content/test/data/accessibility/html/scrollable-overflow-expected-android-assist-data.txt
index ec82a57..5b3d480 100644
--- a/content/test/data/accessibility/html/scrollable-overflow-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/scrollable-overflow-expected-android-assist-data.txt
@@ -1,41 +1,41 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"no overflow" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"clipped large lots of text more text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++EditText text:"ab cd" textSize:13.33 style:0 bundle:[class="textarea scrollable", cols="2", display="inline-block", htmlTag="textarea", rows="1"]
-++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div"]
-++++++TextView text:"ab cd" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", style="overflow: scroll; width: 100px; height: 100px"]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++TextView text:"tiny" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[class="x-overflow-group", display="block", htmlTag="div", role="group"]
-++++View textSize:16.00 style:0 bundle:[class="x-hidden-small not-scrollable", display="block", htmlTag="div", style="overflow-x: hidden;"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"x=hidden" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[class="x-hidden-large scrollable", display="block", htmlTag="div", style="overflow-x: hidden;"]
-++++++View textSize:16.00 style:0 bgColor:-16744448 bundle:[display="block", htmlTag="p", style="width:999px; height:999px; background-color:green;"]
-++++++++TextView text:"x=hidden" textSize:16.00 style:0 bgColor:-16744448 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[class="x-auto scrollable", display="block", htmlTag="div", style="overflow-x: auto;"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"x=auto" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[class="x-scroll scrollable", display="block", htmlTag="div", style="overflow-x: scroll;"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"x=scroll" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++TextView text:"x=visible" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[class="y-overflow-group", display="block", htmlTag="div", role="group"]
-++++View textSize:16.00 style:0 bundle:[class="y-hidden-small not-scrollable", display="block", htmlTag="div", style="overflow-y: hidden;"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"y=hidden" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[class="y-hidden-large scrollable", display="block", htmlTag="div", style="overflow-y: hidden;"]
-++++++View textSize:16.00 style:0 bgColor:-16744448 bundle:[display="block", htmlTag="p", style="width:999px; height:999px; background-color:green;"]
-++++++++TextView text:"y=hidden" textSize:16.00 style:0 bgColor:-16744448 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[class="y-auto scrollable", display="block", htmlTag="div", style="overflow-y: auto;"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"y=auto" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[class="y-scroll scrollable", display="block", htmlTag="div", style="overflow-y: scroll;"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++++TextView text:"y=scroll" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++++TextView text:"y=visible" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"no overflow" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"clipped large lots of text more text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++EditText text:"ab cd" textSize:13.3 style:0 htmlInfo:[{htmlTag="textarea"}, {display="inline-block"}, {cols="2"}, {rows="1"}, {class="textarea scrollable"}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++++TextView text:"ab cd" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="overflow: scroll; width: 100px; height: 100px"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++TextView text:"tiny" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="group"}, {class="x-overflow-group"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="overflow-x: hidden;"}, {class="x-hidden-small not-scrollable"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"x=hidden" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="overflow-x: hidden;"}, {class="x-hidden-large scrollable"}]
+++++++View textSize:16.0 style:0 bgColor:-16744448 htmlInfo:[{htmlTag="p"}, {display="block"}, {style="width:999px; height:999px; background-color:green;"}]
+++++++++TextView text:"x=hidden" textSize:16.0 style:0 bgColor:-16744448 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="overflow-x: auto;"}, {class="x-auto scrollable"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"x=auto" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="overflow-x: scroll;"}, {class="x-scroll scrollable"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"x=scroll" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++TextView text:"x=visible" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {role="group"}, {class="y-overflow-group"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="overflow-y: hidden;"}, {class="y-hidden-small not-scrollable"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"y=hidden" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="overflow-y: hidden;"}, {class="y-hidden-large scrollable"}]
+++++++View textSize:16.0 style:0 bgColor:-16744448 htmlInfo:[{htmlTag="p"}, {display="block"}, {style="width:999px; height:999px; background-color:green;"}]
+++++++++TextView text:"y=hidden" textSize:16.0 style:0 bgColor:-16744448 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="overflow-y: auto;"}, {class="y-auto scrollable"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"y=auto" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="overflow-y: scroll;"}, {class="y-scroll scrollable"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++++TextView text:"y=scroll" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++++TextView text:"y=visible" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/scrollable-textarea-expected-android-assist-data.txt b/content/test/data/accessibility/html/scrollable-textarea-expected-android-assist-data.txt
index 7beb5f9..2bfc845 100644
--- a/content/test/data/accessibility/html/scrollable-textarea-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/scrollable-textarea-expected-android-assist-data.txt
@@ -1,8 +1,8 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++EditText text:"little" textSize:13.33 style:0 bundle:[cols="14", display="inline-block", htmlTag="textarea", rows="2"]
-++++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div"]
-++++++++TextView text:"little" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++++EditText text:"lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text" textSize:13.33 style:0 bundle:[cols="14", display="inline-block", htmlTag="textarea", rows="2"]
-++++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div"]
-++++++++TextView text:"lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++EditText text:"little" textSize:13.3 style:0 htmlInfo:[{htmlTag="textarea"}, {display="inline-block"}, {cols="14"}, {rows="2"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++++++TextView text:"little" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++EditText text:"lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text" textSize:13.3 style:0 htmlInfo:[{htmlTag="textarea"}, {display="inline-block"}, {cols="14"}, {rows="2"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++++++TextView text:"lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text+ lots+of+text" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/search-expected-android-assist-data.txt b/content/test/data/accessibility/html/search-expected-android-assist-data.txt
index a42f41d2..861669a 100644
--- a/content/test/data/accessibility/html/search-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/search-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="search"]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="label"]
-++++++TextView text:"Search element." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++EditText textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="input", type="search"]
-++++++View textSize:13.33 style:0 bundle:[display="flow-root", htmlTag="div"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="search"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="label"}, {display="inline"}]
+++++++TextView text:"Search element." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++EditText textSize:13.3 style:0 htmlInfo:[{htmlTag="input"}, {display="inline-block"}, {type="search"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="flow-root"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/section-expected-android-assist-data.txt b/content/test/data/accessibility/html/section-expected-android-assist-data.txt
index a1be9c28..eda33523 100644
--- a/content/test/data/accessibility/html/section-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/section-expected-android-assist-data.txt
@@ -1,10 +1,10 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="section"]
-++++TextView text:"An unnamed section element gets the section role." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"name" textSize:16.00 style:0 bundle:[aria-label="name", display="block", htmlTag="section"]
-++++TextView text:"Named section element #1 gets the region role" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"Named section element #2 gets the region role" textSize:16.00 style:0 bundle:[aria-labelledby="section1", display="block", htmlTag="section"]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="section1"]
-++++++TextView text:"Named section element #2 gets the region role" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View text:"name" textSize:16.00 style:0 bundle:[display="block", htmlTag="section", title="name"]
-++++TextView text:"Named section element #3 gets the region role" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="section"}, {display="block"}]
+++++TextView text:"An unnamed section element gets the section role." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"name" textSize:16.0 style:0 htmlInfo:[{htmlTag="section"}, {display="block"}, {aria-label="name"}]
+++++TextView text:"Named section element #1 gets the region role" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"Named section element #2 gets the region role" textSize:16.0 style:0 htmlInfo:[{htmlTag="section"}, {display="block"}, {aria-labelledby="section1"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="section1"}]
+++++++TextView text:"Named section element #2 gets the region role" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View text:"name" textSize:16.0 style:0 htmlInfo:[{htmlTag="section"}, {display="block"}, {title="name"}]
+++++TextView text:"Named section element #3 gets the region role" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/select-expected-android-assist-data.txt b/content/test/data/accessibility/html/select-expected-android-assist-data.txt
index 92a3762..43bf443 100644
--- a/content/test/data/accessibility/html/select-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/select-expected-android-assist-data.txt
@@ -1,27 +1,27 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++View text:"Placeholder option" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="select", id="A", name="Select A"]
-++++++View textSize:0.00 style:0 fgColor:0 bundle:[display="", htmlTag=""]
-++++++++View text:"Placeholder option" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value=""]
-++++++++View text:"Option 1" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="1"]
-++++++++View text:"Option 2" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="2"]
-++++View text:"Option 2" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="select", id="B", name="Select B"]
-++++++View textSize:0.00 style:0 fgColor:0 bundle:[display="", htmlTag=""]
-++++++++View text:"Option 1" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="1"]
-++++++++View text:"Option 2" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", selected="", value="2"]
-++++++++View text:"Option 3" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="3"]
-++++View text:"Option 1" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="select", id="C", name="Select C", required=""]
-++++++View textSize:0.00 style:0 fgColor:0 bundle:[display="", htmlTag=""]
-++++++++View text:"Option 1" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="1"]
-++++++++View text:"Option 2" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="2"]
-++++++++View text:"Option 3" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="3"]
-++++View text:"0 selected" textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="select", id="D", multiple="2", name="Select D"]
-++++++View textSize:0.00 style:0 fgColor:0 bundle:[display="", htmlTag=""]
-++++++++View text:"Option 1" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="1"]
-++++++++View text:"Option 2" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="2"]
-++++++++View text:"Option 3" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="3"]
-++++View textSize:13.33 style:0 bgColor:-1052689 bundle:[display="inline-block", htmlTag="select", id="E", name="Select E", size="3"]
-++++++View textSize:0.00 style:0 fgColor:0 bundle:[display="", htmlTag=""]
-++++++++View text:"Option 1" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="1"]
-++++++++View text:"Option 2" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="2"]
-++++++++View text:"Option 3" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="3"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++View text:"Placeholder option" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="select"}, {display="inline-block"}, {id="A"}, {name="Select A"}]
+++++++View textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View text:"Placeholder option" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value=""}]
+++++++++View text:"Option 1" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="1"}]
+++++++++View text:"Option 2" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="2"}]
+++++View text:"Option 2" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="select"}, {display="inline-block"}, {id="B"}, {name="Select B"}]
+++++++View textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View text:"Option 1" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="1"}]
+++++++++View text:"Option 2" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {selected=""}, {value="2"}]
+++++++++View text:"Option 3" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="3"}]
+++++View text:"Option 1" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="select"}, {display="inline-block"}, {id="C"}, {name="Select C"}, {required=""}]
+++++++View textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View text:"Option 1" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="1"}]
+++++++++View text:"Option 2" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="2"}]
+++++++++View text:"Option 3" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="3"}]
+++++View text:"0 selected" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="select"}, {display="inline-block"}, {id="D"}, {multiple="2"}, {name="Select D"}]
+++++++View textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View text:"Option 1" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="1"}]
+++++++++View text:"Option 2" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="2"}]
+++++++++View text:"Option 3" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="3"}]
+++++View textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="select"}, {display="inline-block"}, {id="E"}, {name="Select E"}, {size="3"}]
+++++++View textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View text:"Option 1" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="1"}]
+++++++++View text:"Option 2" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="2"}]
+++++++++View text:"Option 3" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="3"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/selection-container-expected-android-assist-data.txt b/content/test/data/accessibility/html/selection-container-expected-android-assist-data.txt
index d999119..d8fe116 100644
--- a/content/test/data/accessibility/html/selection-container-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/selection-container-expected-android-assist-data.txt
@@ -1,8 +1,8 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++View text:"selection_list" textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-label="selection_list", display="inline-block", htmlTag="select", id="listbox", size="10"]
-++++++View textSize:0.00 style:0 fgColor:0 bundle:[display="", htmlTag=""]
-++++++++View text:"One" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", id="listbox_option_enabled_one", value="listbox_e1"]
-++++++++View text:"Two" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="listbox_e2"]
-++++++++View text:"Three" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="listbox_e3"]
-++++++++View text:"Four" textSize:0.00 style:0 fgColor:0 bundle:[display="block", htmlTag="option", value="listbox_e4"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++View text:"selection_list" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="select"}, {display="inline-block"}, {aria-label="selection_list"}, {id="listbox"}, {size="10"}]
+++++++View textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View text:"One" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {id="listbox_option_enabled_one"}, {value="listbox_e1"}]
+++++++++View text:"Two" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="listbox_e2"}]
+++++++++View text:"Three" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="listbox_e3"}]
+++++++++View text:"Four" textSize:0.0 style:0 fgColor:0 htmlInfo:[{htmlTag="option"}, {display="block"}, {value="listbox_e4"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/simple_spans-expected-android-assist-data.txt b/content/test/data/accessibility/html/simple_spans-expected-android-assist-data.txt
index 5ed1967..55e1641 100644
--- a/content/test/data/accessibility/html/simple_spans-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/simple_spans-expected-android-assist-data.txt
@@ -1,7 +1,7 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="s1"]
-++++++TextView text:"Some text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="span", id="s2"]
-++++++TextView text:"3.14159" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="s1"}]
+++++++TextView text:"Some text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="span"}, {display="inline"}, {id="s2"}]
+++++++TextView text:"3.14159" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/small-expected-android-assist-data.txt b/content/test/data/accessibility/html/small-expected-android-assist-data.txt
index f92c79f4..0a5bf8f 100644
--- a/content/test/data/accessibility/html/small-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/small-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"Chromium" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"open source project" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"Chromium" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"open source project" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/span-expected-android-assist-data.txt b/content/test/data/accessibility/html/span-expected-android-assist-data.txt
index 92c9cf99..6db7d87e 100644
--- a/content/test/data/accessibility/html/span-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/span-expected-android-assist-data.txt
@@ -1,70 +1,70 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"This" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"paragraph has " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"in" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"spans" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"E1. Eat" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#", htmlTag="a"]
-++++++TextView text:"space" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"E2. Eat" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#", htmlTag="a"]
-++++++TextView text:"space" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"E3. Eat" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:3 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#", htmlTag="a"]
-++++++TextView text:"space" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#", htmlTag="a"]
-++++++TextView text:"E4. Eat" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"space" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#", htmlTag="a"]
-++++++TextView text:"E5. Eat" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++TextView text:"space" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++View textSize:16.00 style:4 fgColor:-16776978 bundle:[display="inline", href="#", htmlTag="a"]
-++++++TextView text:"E6. Eat" textSize:16.00 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:3 bundle:[display="", htmlTag=""]
-++++TextView text:"space" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"K1. Keep" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"space" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"K2. Keep" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++TextView text:"space" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"K3. Keep" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:3 bundle:[display="", htmlTag=""]
-++++TextView text:"space" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"K4. Keep " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"space" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"K5. Keep" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"space" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"K6. Keep " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"space" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"K7. Keep" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" space" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"K8. Keep" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"space" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"This" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"paragraph has " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"in" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"spans" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"E1. Eat" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#"}]
+++++++TextView text:"space" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"E2. Eat" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#"}]
+++++++TextView text:"space" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"E3. Eat" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:3 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#"}]
+++++++TextView text:"space" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#"}]
+++++++TextView text:"E4. Eat" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"space" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#"}]
+++++++TextView text:"E5. Eat" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"space" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++View textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#"}]
+++++++TextView text:"E6. Eat" textSize:16.0 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:3 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"space" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"K1. Keep" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"space" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"K2. Keep" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"space" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"K3. Keep" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:3 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"space" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"K4. Keep " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"space" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"K5. Keep" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"space" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"K6. Keep " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"space" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"K7. Keep" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" space" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"K8. Keep" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"space" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/spans-separated-by-space-expected-android-assist-data.txt b/content/test/data/accessibility/html/spans-separated-by-space-expected-android-assist-data.txt
index f1fdd3a..f628ceca 100644
--- a/content/test/data/accessibility/html/spans-separated-by-space-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/spans-separated-by-space-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++TextView text:"Hello" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"world" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++TextView text:"Hello" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"world" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/static-list-expected-android-assist-data.txt b/content/test/data/accessibility/html/static-list-expected-android-assist-data.txt
index 30df872..0668801 100644
--- a/content/test/data/accessibility/html/static-list-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/static-list-expected-android-assist-data.txt
@@ -1,11 +1,11 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ol"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"1. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"Kirk" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"2. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"Picard" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"3. " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"Janeway" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ol"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"1. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"Kirk" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"2. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"Picard" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"3. " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"Janeway" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/strong-expected-android-assist-data.txt b/content/test/data/accessibility/html/strong-expected-android-assist-data.txt
index cda7b5a..5c595a17 100644
--- a/content/test/data/accessibility/html/strong-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/strong-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++TextView text:"Strong text" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++TextView text:"Strong text" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/sub-expected-android-assist-data.txt b/content/test/data/accessibility/html/sub-expected-android-assist-data.txt
index 275667a6..4ccca753 100644
--- a/content/test/data/accessibility/html/sub-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/sub-expected-android-assist-data.txt
@@ -1,21 +1,21 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"This text contains " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:13.33 style:0 bundle:[display="inline", htmlTag="sub"]
-++++++TextView text:"subscript" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" text." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"H" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:13.33 style:0 bundle:[display="inline", htmlTag="sub"]
-++++++TextView text:" " textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:13.33 style:8 bundle:[display="inline", htmlTag="del"]
-++++++++View textSize:13.33 style:8 bundle:[display="inline", htmlTag="span", tabindex="0"]
-++++++++++View text:"oops" textSize:13.33 style:8 bundle:[display="inline", htmlTag="span", title="oops"]
-++++++++++++TextView text:"3" textSize:13.33 style:8 bundle:[display="", htmlTag=""]
-++++++TextView text:" " textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:13.33 style:4 bundle:[display="inline", htmlTag="ins"]
-++++++++View textSize:13.33 style:4 fgColor:-16776978 bundle:[display="inline", href="#", htmlTag="a"]
-++++++++++View text:"better" textSize:13.33 style:4 fgColor:-16776978 bundle:[display="inline", htmlTag="span", title="better"]
-++++++++++++TextView text:"2" textSize:13.33 style:4 fgColor:-16776978 bundle:[display="", htmlTag=""]
-++++++TextView text:" " textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"O" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"This text contains " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="sub"}, {display="inline"}]
+++++++TextView text:"subscript" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" text." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"H" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="sub"}, {display="inline"}]
+++++++TextView text:" " textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:13.3 style:8 htmlInfo:[{htmlTag="del"}, {display="inline"}]
+++++++++View textSize:13.3 style:8 htmlInfo:[{htmlTag="span"}, {display="inline"}, {tabindex="0"}]
+++++++++++View text:"oops" textSize:13.3 style:8 htmlInfo:[{htmlTag="span"}, {display="inline"}, {title="oops"}]
+++++++++++++TextView text:"3" textSize:13.3 style:8 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:" " textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:13.3 style:4 htmlInfo:[{htmlTag="ins"}, {display="inline"}]
+++++++++View textSize:13.3 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#"}]
+++++++++++View text:"better" textSize:13.3 style:4 fgColor:-16776978 htmlInfo:[{htmlTag="span"}, {display="inline"}, {title="better"}]
+++++++++++++TextView text:"2" textSize:13.3 style:4 fgColor:-16776978 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++TextView text:" " textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"O" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/summary-expected-android-assist-data.txt b/content/test/data/accessibility/html/summary-expected-android-assist-data.txt
index 44dbe81..4b42c517 100644
--- a/content/test/data/accessibility/html/summary-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/summary-expected-android-assist-data.txt
@@ -1,7 +1,7 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="details"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="summary"]
-++++++TextView text:"details tag" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="details"]
-++++View text:"name details #2" textSize:16.00 style:0 bundle:[aria-label="name", display="list-item", htmlTag="summary"]
-++++++TextView text:"details #2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="details"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="summary"}, {display="list-item"}]
+++++++TextView text:"details tag" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="details"}, {display="block"}]
+++++View text:"name details #2" textSize:16.0 style:0 htmlInfo:[{htmlTag="summary"}, {display="list-item"}, {aria-label="name"}]
+++++++TextView text:"details #2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/sup-expected-android-assist-data.txt b/content/test/data/accessibility/html/sup-expected-android-assist-data.txt
index 6fcf5a3..35a87fe 100644
--- a/content/test/data/accessibility/html/sup-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/sup-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"This text contains" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:13.33 style:0 bundle:[display="inline", htmlTag="sup"]
-++++++TextView text:"superscript" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"text." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"This text contains" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="sup"}, {display="inline"}]
+++++++TextView text:"superscript" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"text." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/svg-as-object-source-expected-android-assist-data.txt b/content/test/data/accessibility/html/svg-as-object-source-expected-android-assist-data.txt
index e9abd7f..f333a28 100644
--- a/content/test/data/accessibility/html/svg-as-object-source-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/svg-as-object-source-expected-android-assist-data.txt
@@ -1,18 +1,18 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++View text:"object without space" textSize:16.00 style:0 bundle:[aria-label="object without space", data="svg-face.svg", display="inline", htmlTag="object", type="image/svg+xml"]
-++++++View textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++++++++Image textSize:16.00 style:0 bundle:[display="block", height="400", htmlTag="svg", viewbox="0 0 400 400", width="400", xmlns="http://www.w3.org/2000/svg"]
-++++++++++Button text:"face" textSize:16.00 style:0 bundle:[aria-label="face", cx="200", cy="200", display="inline", fill="yellow", htmlTag="circle", id="face", r="200", role="button", stroke="red", stroke-width="1"]
-++++++++++Button text:"left-eye" textSize:16.00 style:0 bundle:[aria-label="left-eye", cx="120", cy="180", display="inline", fill="black", htmlTag="ellipse", id="left-eye", role="button", rx="18", ry="33"]
-++++++++++Button text:"right-eye" textSize:16.00 style:0 bundle:[aria-label="right-eye", cx="280", cy="120", display="inline", fill="black", htmlTag="ellipse", id="right-eye", role="button", rx="18", ry="33"]
-++++++++++Button text:"nose" textSize:16.00 style:0 bundle:[aria-label="nose", cx="200", cy="220", display="inline", fill="black", htmlTag="ellipse", id="nose", role="button", rx="8", ry="15"]
-++++++++++Button text:"smile" textSize:16.00 style:0 bundle:[aria-label="smile", d="M120,280 Q200,330 290,280", display="inline", fill="none", htmlTag="path", id="smile", role="button", stroke="black", stroke-linecap="round", stroke-width="10"]
-++++View text:"object with space" textSize:16.00 style:0 bundle:[aria-label="object with space", data="svg-face.svg", display="inline", htmlTag="object", type="image/svg+xml"]
-++++++View textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++++++++Image textSize:16.00 style:0 bundle:[display="block", height="400", htmlTag="svg", viewbox="0 0 400 400", width="400", xmlns="http://www.w3.org/2000/svg"]
-++++++++++Button text:"face" textSize:16.00 style:0 bundle:[aria-label="face", cx="200", cy="200", display="inline", fill="yellow", htmlTag="circle", id="face", r="200", role="button", stroke="red", stroke-width="1"]
-++++++++++Button text:"left-eye" textSize:16.00 style:0 bundle:[aria-label="left-eye", cx="120", cy="180", display="inline", fill="black", htmlTag="ellipse", id="left-eye", role="button", rx="18", ry="33"]
-++++++++++Button text:"right-eye" textSize:16.00 style:0 bundle:[aria-label="right-eye", cx="280", cy="120", display="inline", fill="black", htmlTag="ellipse", id="right-eye", role="button", rx="18", ry="33"]
-++++++++++Button text:"nose" textSize:16.00 style:0 bundle:[aria-label="nose", cx="200", cy="220", display="inline", fill="black", htmlTag="ellipse", id="nose", role="button", rx="8", ry="15"]
-++++++++++Button text:"smile" textSize:16.00 style:0 bundle:[aria-label="smile", d="M120,280 Q200,330 290,280", display="inline", fill="none", htmlTag="path", id="smile", role="button", stroke="black", stroke-linecap="round", stroke-width="10"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++View text:"object without space" textSize:16.0 style:0 htmlInfo:[{htmlTag="object"}, {display="inline"}, {aria-label="object without space"}, {data="svg-face.svg"}, {type="image/svg+xml"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++++++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="block"}, {height="400"}, {viewbox="0 0 400 400"}, {width="400"}, {xmlns="http://www.w3.org/2000/svg"}]
+++++++++++Button text:"face" textSize:16.0 style:0 htmlInfo:[{htmlTag="circle"}, {display="inline"}, {aria-label="face"}, {cx="200"}, {cy="200"}, {fill="yellow"}, {id="face"}, {r="200"}, {role="button"}, {stroke="red"}, {stroke-width="1"}]
+++++++++++Button text:"left-eye" textSize:16.0 style:0 htmlInfo:[{htmlTag="ellipse"}, {display="inline"}, {aria-label="left-eye"}, {cx="120"}, {cy="180"}, {fill="black"}, {id="left-eye"}, {role="button"}, {rx="18"}, {ry="33"}]
+++++++++++Button text:"right-eye" textSize:16.0 style:0 htmlInfo:[{htmlTag="ellipse"}, {display="inline"}, {aria-label="right-eye"}, {cx="280"}, {cy="120"}, {fill="black"}, {id="right-eye"}, {role="button"}, {rx="18"}, {ry="33"}]
+++++++++++Button text:"nose" textSize:16.0 style:0 htmlInfo:[{htmlTag="ellipse"}, {display="inline"}, {aria-label="nose"}, {cx="200"}, {cy="220"}, {fill="black"}, {id="nose"}, {role="button"}, {rx="8"}, {ry="15"}]
+++++++++++Button text:"smile" textSize:16.0 style:0 htmlInfo:[{htmlTag="path"}, {display="inline"}, {aria-label="smile"}, {d="M120,280 Q200,330 290,280"}, {fill="none"}, {id="smile"}, {role="button"}, {stroke="black"}, {stroke-linecap="round"}, {stroke-width="10"}]
+++++View text:"object with space" textSize:16.0 style:0 htmlInfo:[{htmlTag="object"}, {display="inline"}, {aria-label="object with space"}, {data="svg-face.svg"}, {type="image/svg+xml"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++++++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="block"}, {height="400"}, {viewbox="0 0 400 400"}, {width="400"}, {xmlns="http://www.w3.org/2000/svg"}]
+++++++++++Button text:"face" textSize:16.0 style:0 htmlInfo:[{htmlTag="circle"}, {display="inline"}, {aria-label="face"}, {cx="200"}, {cy="200"}, {fill="yellow"}, {id="face"}, {r="200"}, {role="button"}, {stroke="red"}, {stroke-width="1"}]
+++++++++++Button text:"left-eye" textSize:16.0 style:0 htmlInfo:[{htmlTag="ellipse"}, {display="inline"}, {aria-label="left-eye"}, {cx="120"}, {cy="180"}, {fill="black"}, {id="left-eye"}, {role="button"}, {rx="18"}, {ry="33"}]
+++++++++++Button text:"right-eye" textSize:16.0 style:0 htmlInfo:[{htmlTag="ellipse"}, {display="inline"}, {aria-label="right-eye"}, {cx="280"}, {cy="120"}, {fill="black"}, {id="right-eye"}, {role="button"}, {rx="18"}, {ry="33"}]
+++++++++++Button text:"nose" textSize:16.0 style:0 htmlInfo:[{htmlTag="ellipse"}, {display="inline"}, {aria-label="nose"}, {cx="200"}, {cy="220"}, {fill="black"}, {id="nose"}, {role="button"}, {rx="8"}, {ry="15"}]
+++++++++++Button text:"smile" textSize:16.0 style:0 htmlInfo:[{htmlTag="path"}, {display="inline"}, {aria-label="smile"}, {d="M120,280 Q200,330 290,280"}, {fill="none"}, {id="smile"}, {role="button"}, {stroke="black"}, {stroke-linecap="round"}, {stroke-width="10"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/svg-child-of-button-expected-android-assist-data.txt b/content/test/data/accessibility/html/svg-child-of-button-expected-android-assist-data.txt
index 6d79a9f..6bfd4c5 100644
--- a/content/test/data/accessibility/html/svg-child-of-button-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/svg-child-of-button-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Button text:"Search" textSize:13.33 style:0 bgColor:-1052689 bundle:[aria-label="Search", display="inline-block", htmlTag="button"]
-++++++Image textSize:13.33 style:0 bundle:[class="button-child-icon", display="inline", height="24px", htmlTag="svg", viewbox="0 0 24 24", width="24px", xmlns="http://www.w3.org/2000/svg"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Button text:"Search" textSize:13.3 style:0 bgColor:-1052689 htmlInfo:[{htmlTag="button"}, {display="inline-block"}, {aria-label="Search"}]
+++++++Image textSize:13.3 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {height="24px"}, {viewbox="0 0 24 24"}, {width="24px"}, {xmlns="http://www.w3.org/2000/svg"}, {class="button-child-icon"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/svg-child-of-svg-expected-android-assist-data.txt b/content/test/data/accessibility/html/svg-child-of-svg-expected-android-assist-data.txt
index 707e53e4..93835fd 100644
--- a/content/test/data/accessibility/html/svg-child-of-svg-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/svg-child-of-svg-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Image text:"Has two simple children" textSize:16.00 style:0 bundle:[aria-label="Has two simple children", display="inline", htmlTag="svg"]
-++++Image text:"Has two focusable children" textSize:16.00 style:0 bundle:[aria-label="Has two focusable children", display="inline", htmlTag="svg"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="svg", tabindex="0", x="10"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="svg", tabindex="0", x="100"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Image text:"Has two simple children" textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {aria-label="Has two simple children"}]
+++++Image text:"Has two focusable children" textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {aria-label="Has two focusable children"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {tabindex="0"}, {x="10"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {tabindex="0"}, {x="100"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/svg-desc-in-group-expected-android-assist-data.txt b/content/test/data/accessibility/html/svg-desc-in-group-expected-android-assist-data.txt
index 62131204..69374e6 100644
--- a/content/test/data/accessibility/html/svg-desc-in-group-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/svg-desc-in-group-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Image textSize:16.00 style:0 bundle:[display="inline", height="300", htmlTag="svg", width="300"]
-++++++View text:"Group with circle and text" textSize:16.00 style:0 bundle:[display="inline", htmlTag="g"]
-++++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="text"]
-++++++++++TextView text:"hello world" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {height="300"}, {width="300"}]
+++++++View text:"Group with circle and text" textSize:16.0 style:0 htmlInfo:[{htmlTag="g"}, {display="inline"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="text"}, {display="block"}]
+++++++++++TextView text:"hello world" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/svg-expected-android-assist-data.txt b/content/test/data/accessibility/html/svg-expected-android-assist-data.txt
index cf13964..343bc3d 100644
--- a/content/test/data/accessibility/html/svg-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/svg-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Image text:"svg SVG Title Tag" textSize:16.00 style:0 bundle:[aria-label="svg", display="inline", htmlTag="svg"]
-++++++View textSize:16.00 style:0 bundle:[display="block", fill="red", htmlTag="text", x="150", y="130"]
-++++++++TextView text:"Test" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Image text:"svg SVG Title Tag" textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {aria-label="svg"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="text"}, {display="block"}, {fill="red"}, {x="150"}, {y="130"}]
+++++++++TextView text:"Test" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/svg-symbol-with-role-expected-android-assist-data.txt b/content/test/data/accessibility/html/svg-symbol-with-role-expected-android-assist-data.txt
index 58c4cec..4c10e72 100644
--- a/content/test/data/accessibility/html/svg-symbol-with-role-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/svg-symbol-with-role-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Image textSize:16.00 style:0 bundle:[class="Symbol with role", display="inline", htmlTag="svg"]
-++++++Button text:"Click me!" textSize:16.00 style:0 bundle:[aria-roledescription="fancy button", display="inline", height="10", htmlTag="svg", id="myRect", role="button", width="10"]
-++++++Button text:"Click me!" textSize:16.00 style:0 bundle:[aria-roledescription="fancy button", display="inline", height="10", htmlTag="svg", id="myRect", role="button", width="10"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {class="Symbol with role"}]
+++++++Button text:"Click me!" textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {aria-roledescription="fancy button"}, {height="10"}, {id="myRect"}, {role="button"}, {width="10"}]
+++++++Button text:"Click me!" textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {aria-roledescription="fancy button"}, {height="10"}, {id="myRect"}, {role="button"}, {width="10"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/svg-text-alternative-computation-expected-android-assist-data.txt b/content/test/data/accessibility/html/svg-text-alternative-computation-expected-android-assist-data.txt
index aef9351ac..9709f87 100644
--- a/content/test/data/accessibility/html/svg-text-alternative-computation-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/svg-text-alternative-computation-expected-android-assist-data.txt
@@ -1,41 +1,41 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Image textSize:16.00 style:0 bundle:[class="name-aria-labelledby", display="inline", htmlTag="svg"]
-++++++View text:"Link (from aria-labelledby) Link (from title)" textSize:16.00 style:0 bundle:[aria-label="Link (from aria-label)", aria-labelledby="link-label", display="inline", href="foo.html", htmlTag="a", title="Link (from xlink:title)"]
-++++Image textSize:16.00 style:0 bundle:[class="name-aria-label", display="inline", htmlTag="svg"]
-++++++View text:"Link (from aria-label) Link (from title)" textSize:16.00 style:0 bundle:[aria-label="Link (from aria-label)", display="inline", href="foo.html", htmlTag="a", title="Link (from xlink:title)"]
-++++Image textSize:16.00 style:0 bundle:[class="name-title", display="inline", htmlTag="svg"]
-++++++View text:"Link (from title) Link (from xlink:title)" textSize:16.00 style:0 bundle:[display="inline", href="foo.html", htmlTag="a", title="Link (from xlink:title)"]
-++++Image textSize:16.00 style:0 bundle:[class="name-xlink-title", display="inline", htmlTag="svg"]
-++++++View text:"Link (from xlink:title)" textSize:16.00 style:0 bundle:[display="inline", href="foo.html", htmlTag="a", title="Link (from xlink:title)"]
-++++Image textSize:16.00 style:0 bundle:[class="name-aria-labelledby", display="inline", htmlTag="svg"]
-++++++View text:"Circle (from aria-labelledby)" textSize:16.00 style:0 bundle:[aria-labelledby="circle-label", cx="10", cy="10", display="inline", htmlTag="circle", r="5"]
-++++Image textSize:16.00 style:0 bundle:[class="name-aria-label", display="inline", htmlTag="svg"]
-++++++View text:"Circle (from aria-label)" textSize:16.00 style:0 bundle:[aria-label="Circle (from aria-label)", cx="10", cy="10", display="inline", htmlTag="circle", r="5"]
-++++Image textSize:16.00 style:0 bundle:[class="name-title", display="inline", htmlTag="svg"]
-++++++View text:"Circle (from title)" textSize:16.00 style:0 bundle:[cx="10", cy="10", display="inline", htmlTag="circle", r="5"]
-++++Image textSize:16.00 style:0 bundle:[class="name-use-title", display="inline", htmlTag="svg"]
-++++++View text:"Circle (From first use element's title)" textSize:16.00 style:0 bundle:[display="inline", href="#myCircle", htmlTag="use", style="opacity:1.0", x="5", y="5"]
-++++++View text:"Circle (From second use element's title)" textSize:16.00 style:0 bundle:[display="inline", href="#myCircle", htmlTag="use", style="opacity:0.5", x="20", y="5"]
-++++Image textSize:16.00 style:0 bundle:[class="name-symbol-title", display="inline", htmlTag="svg"]
-++++++View text:"Rectangle Symbol (From symbol's title)" textSize:16.00 style:0 bundle:[display="inline", height="10", htmlTag="svg", id="myRect", width="10"]
-++++++View text:"Rectangle Symbol (From symbol's title)" textSize:16.00 style:0 bundle:[display="inline", height="10", htmlTag="svg", id="myRect", width="10"]
-++++Image textSize:16.00 style:0 bundle:[class="description-aria-describedby", display="inline", htmlTag="svg"]
-++++++View text:"Link (from title) Link (from aria-describedby)" textSize:16.00 style:0 bundle:[aria-describedby="link-description", aria-description="Link (from aria-description)", display="inline", href="foo.html", htmlTag="a", title="Link (from xlink:title)"]
-++++Image textSize:16.00 style:0 bundle:[class="description-aria-description", display="inline", htmlTag="svg"]
-++++++View text:"Link (from title) Link (from aria-description)" textSize:16.00 style:0 bundle:[aria-description="Link (from aria-description)", display="inline", href="foo.html", htmlTag="a", title="Link (from xlink:title)"]
-++++Image textSize:16.00 style:0 bundle:[class="description-desc", display="inline", htmlTag="svg"]
-++++++View text:"Link (from title) Link (from desc)" textSize:16.00 style:0 bundle:[display="inline", href="foo.html", htmlTag="a", title="Link (from xlink:title)"]
-++++Image textSize:16.00 style:0 bundle:[class="description-title", display="inline", htmlTag="svg"]
-++++++View text:"Link (from aria-label) Link (from title)" textSize:16.00 style:0 bundle:[aria-label="Link (from aria-label)", display="inline", href="foo.html", htmlTag="a", title="Link (from xlink:title)"]
-++++Image textSize:16.00 style:0 bundle:[class="description-xlink-title", display="inline", htmlTag="svg"]
-++++++View text:"Link (from title) Link (from xlink:title)" textSize:16.00 style:0 bundle:[display="inline", href="foo.html", htmlTag="a", title="Link (from xlink:title)"]
-++++Image textSize:16.00 style:0 bundle:[class="description-use-desc", display="inline", htmlTag="svg"]
-++++++View text:"Circle (From first use element's desc)" textSize:16.00 style:0 bundle:[display="inline", href="#myCircle2", htmlTag="use", style="opacity:1.0", x="5", y="5"]
-++++++View text:"Circle (From second use element's desc)" textSize:16.00 style:0 bundle:[display="inline", href="#myCircle2", htmlTag="use", style="opacity:0.5", x="20", y="5"]
-++++Image textSize:16.00 style:0 bundle:[class="description-use-title", display="inline", htmlTag="svg"]
-++++++View text:"Circle 1 Circle (From first use element's title)" textSize:16.00 style:0 bundle:[aria-label="Circle 1", display="inline", href="#myCircle3", htmlTag="use", style="opacity:1.0", x="5", y="5"]
-++++++View text:"Circle 2 Circle (From second use element's title)" textSize:16.00 style:0 bundle:[aria-label="Circle 2", display="inline", href="#myCircle3", htmlTag="use", style="opacity:0.5", x="20", y="5"]
-++++Image textSize:16.00 style:0 bundle:[class="desc-symbol-desc", display="inline", htmlTag="svg"]
-++++++View text:"Rectangle Symbol (From symbol's desc)" textSize:16.00 style:0 bundle:[display="inline", height="10", htmlTag="svg", id="myRect2", width="10"]
-++++++View text:"Rectangle Symbol (From symbol's desc)" textSize:16.00 style:0 bundle:[display="inline", height="10", htmlTag="svg", id="myRect2", width="10"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {class="name-aria-labelledby"}]
+++++++View text:"Link (from aria-labelledby) Link (from title)" textSize:16.0 style:0 htmlInfo:[{htmlTag="a"}, {display="inline"}, {aria-label="Link (from aria-label)"}, {aria-labelledby="link-label"}, {href="foo.html"}, {title="Link (from xlink:title)"}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {class="name-aria-label"}]
+++++++View text:"Link (from aria-label) Link (from title)" textSize:16.0 style:0 htmlInfo:[{htmlTag="a"}, {display="inline"}, {aria-label="Link (from aria-label)"}, {href="foo.html"}, {title="Link (from xlink:title)"}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {class="name-title"}]
+++++++View text:"Link (from title) Link (from xlink:title)" textSize:16.0 style:0 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="foo.html"}, {title="Link (from xlink:title)"}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {class="name-xlink-title"}]
+++++++View text:"Link (from xlink:title)" textSize:16.0 style:0 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="foo.html"}, {title="Link (from xlink:title)"}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {class="name-aria-labelledby"}]
+++++++View text:"Circle (from aria-labelledby)" textSize:16.0 style:0 htmlInfo:[{htmlTag="circle"}, {display="inline"}, {aria-labelledby="circle-label"}, {cx="10"}, {cy="10"}, {r="5"}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {class="name-aria-label"}]
+++++++View text:"Circle (from aria-label)" textSize:16.0 style:0 htmlInfo:[{htmlTag="circle"}, {display="inline"}, {aria-label="Circle (from aria-label)"}, {cx="10"}, {cy="10"}, {r="5"}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {class="name-title"}]
+++++++View text:"Circle (from title)" textSize:16.0 style:0 htmlInfo:[{htmlTag="circle"}, {display="inline"}, {cx="10"}, {cy="10"}, {r="5"}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {class="name-use-title"}]
+++++++View text:"Circle (From first use element's title)" textSize:16.0 style:0 htmlInfo:[{htmlTag="use"}, {display="inline"}, {href="#myCircle"}, {style="opacity:1.0"}, {x="5"}, {y="5"}]
+++++++View text:"Circle (From second use element's title)" textSize:16.0 style:0 htmlInfo:[{htmlTag="use"}, {display="inline"}, {href="#myCircle"}, {style="opacity:0.5"}, {x="20"}, {y="5"}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {class="name-symbol-title"}]
+++++++View text:"Rectangle Symbol (From symbol's title)" textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {height="10"}, {id="myRect"}, {width="10"}]
+++++++View text:"Rectangle Symbol (From symbol's title)" textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {height="10"}, {id="myRect"}, {width="10"}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {class="description-aria-describedby"}]
+++++++View text:"Link (from title) Link (from aria-describedby)" textSize:16.0 style:0 htmlInfo:[{htmlTag="a"}, {display="inline"}, {aria-describedby="link-description"}, {aria-description="Link (from aria-description)"}, {href="foo.html"}, {title="Link (from xlink:title)"}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {class="description-aria-description"}]
+++++++View text:"Link (from title) Link (from aria-description)" textSize:16.0 style:0 htmlInfo:[{htmlTag="a"}, {display="inline"}, {aria-description="Link (from aria-description)"}, {href="foo.html"}, {title="Link (from xlink:title)"}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {class="description-desc"}]
+++++++View text:"Link (from title) Link (from desc)" textSize:16.0 style:0 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="foo.html"}, {title="Link (from xlink:title)"}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {class="description-title"}]
+++++++View text:"Link (from aria-label) Link (from title)" textSize:16.0 style:0 htmlInfo:[{htmlTag="a"}, {display="inline"}, {aria-label="Link (from aria-label)"}, {href="foo.html"}, {title="Link (from xlink:title)"}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {class="description-xlink-title"}]
+++++++View text:"Link (from title) Link (from xlink:title)" textSize:16.0 style:0 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="foo.html"}, {title="Link (from xlink:title)"}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {class="description-use-desc"}]
+++++++View text:"Circle (From first use element's desc)" textSize:16.0 style:0 htmlInfo:[{htmlTag="use"}, {display="inline"}, {href="#myCircle2"}, {style="opacity:1.0"}, {x="5"}, {y="5"}]
+++++++View text:"Circle (From second use element's desc)" textSize:16.0 style:0 htmlInfo:[{htmlTag="use"}, {display="inline"}, {href="#myCircle2"}, {style="opacity:0.5"}, {x="20"}, {y="5"}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {class="description-use-title"}]
+++++++View text:"Circle 1 Circle (From first use element's title)" textSize:16.0 style:0 htmlInfo:[{htmlTag="use"}, {display="inline"}, {aria-label="Circle 1"}, {href="#myCircle3"}, {style="opacity:1.0"}, {x="5"}, {y="5"}]
+++++++View text:"Circle 2 Circle (From second use element's title)" textSize:16.0 style:0 htmlInfo:[{htmlTag="use"}, {display="inline"}, {aria-label="Circle 2"}, {href="#myCircle3"}, {style="opacity:0.5"}, {x="20"}, {y="5"}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {class="desc-symbol-desc"}]
+++++++View text:"Rectangle Symbol (From symbol's desc)" textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {height="10"}, {id="myRect2"}, {width="10"}]
+++++++View text:"Rectangle Symbol (From symbol's desc)" textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {height="10"}, {id="myRect2"}, {width="10"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/svg-with-clickable-rect-expected-android-assist-data.txt b/content/test/data/accessibility/html/svg-with-clickable-rect-expected-android-assist-data.txt
index c99de1f..bc74a66 100644
--- a/content/test/data/accessibility/html/svg-with-clickable-rect-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/svg-with-clickable-rect-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Image textSize:16.00 style:0 bundle:[display="inline", htmlTag="svg"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", height="10", htmlTag="rect", id="clickable", width="10"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="rect"}, {display="inline"}, {height="10"}, {id="clickable"}, {width="10"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/svg-with-foreign-object-expected-android-assist-data.txt b/content/test/data/accessibility/html/svg-with-foreign-object-expected-android-assist-data.txt
index e9a6489f..e4c361a 100644
--- a/content/test/data/accessibility/html/svg-with-foreign-object-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/svg-with-foreign-object-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Image textSize:16.00 style:0 bundle:[display="inline", htmlTag="svg"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p", xmlns="http://www.w3.org/1999/xhtml"]
-++++++++TextView text:"Hello world" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Image textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}, {xmlns="http://www.w3.org/1999/xhtml"}]
+++++++++TextView text:"Hello world" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/svg-with-link-to-document-expected-android-assist-data.txt b/content/test/data/accessibility/html/svg-with-link-to-document-expected-android-assist-data.txt
index 61cf9f9..9d99fa5 100644
--- a/content/test/data/accessibility/html/svg-with-link-to-document-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/svg-with-link-to-document-expected-android-assist-data.txt
@@ -1,4 +1,4 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Image text:"svg" textSize:16.00 style:0 bundle:[aria-label="svg", display="inline", height="10", htmlTag="svg", viewbox="0 0 10 10", width="10"]
-++++++View text:"svg-with-link-to-document" textSize:16.00 style:0 bundle:[display="inline", href="#", htmlTag="a"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Image text:"svg" textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {aria-label="svg"}, {height="10"}, {viewbox="0 0 10 10"}, {width="10"}]
+++++++View text:"svg-with-link-to-document" textSize:16.0 style:0 htmlInfo:[{htmlTag="a"}, {display="inline"}, {href="#"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/svg-with-non-link-anchors-expected-android-assist-data.txt b/content/test/data/accessibility/html/svg-with-non-link-anchors-expected-android-assist-data.txt
index 0671fe2..47ffd3f 100644
--- a/content/test/data/accessibility/html/svg-with-non-link-anchors-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/svg-with-non-link-anchors-expected-android-assist-data.txt
@@ -1,10 +1,10 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++Image text:"Text descendants" textSize:16.00 style:0 bundle:[aria-label="Text descendants", display="inline", htmlTag="svg"]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="text"]
-++++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="a", tabindex="0"]
-++++++++++TextView text:"focusable" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="block", htmlTag="text"]
-++++++++TextView text:"not focusable" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++Image text:"Not text descendants" textSize:16.00 style:0 bundle:[aria-label="Not text descendants", display="inline", htmlTag="svg"]
-++++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="a", tabindex="0"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++Image text:"Text descendants" textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {aria-label="Text descendants"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="text"}, {display="block"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="a"}, {display="inline"}, {tabindex="0"}]
+++++++++++TextView text:"focusable" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="text"}, {display="block"}]
+++++++++TextView text:"not focusable" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++Image text:"Not text descendants" textSize:16.0 style:0 htmlInfo:[{htmlTag="svg"}, {display="inline"}, {aria-label="Not text descendants"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="a"}, {display="inline"}, {tabindex="0"}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/tabindex-expose-children-expected-android-assist-data.txt b/content/test/data/accessibility/html/tabindex-expose-children-expected-android-assist-data.txt
index c17e8cd1..19c9c862 100644
--- a/content/test/data/accessibility/html/tabindex-expose-children-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/tabindex-expose-children-expected-android-assist-data.txt
@@ -1,14 +1,14 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="table", htmlTag="table"]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"1." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"2." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", tabindex="0"]
-++++View textSize:16.00 style:0 bundle:[display="table", htmlTag="table"]
-++++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++++TextView text:"3." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++++TextView text:"4." textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"1." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"2." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {tabindex="0"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++++TextView text:"3." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++++TextView text:"4." textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/table-focusable-sections-expected-android-assist-data.txt b/content/test/data/accessibility/html/table-focusable-sections-expected-android-assist-data.txt
index 3aeafe5..c7a1193 100644
--- a/content/test/data/accessibility/html/table-focusable-sections-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/table-focusable-sections-expected-android-assist-data.txt
@@ -1,25 +1,25 @@
-WebView text:"Table example - focusable thead, tbody, tfoot" textSize:16.00 style:0 bundle:[display="", htmlTag="#document", metadata="[<title>Table example - focusable thead, tbody, tfoot</title>]"]
-++GridView textSize:16.00 style:0 bundle:[border="1", display="table", htmlTag="table"]
-++++View textSize:16.00 style:0 bundle:[display="table-header-group", htmlTag="thead", tabindex="0"]
-++++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++++View textSize:16.00 style:1 bundle:[display="table-cell", htmlTag="th"]
-++++++++++TextView text:"Sum" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:1 bundle:[display="table-cell", htmlTag="th"]
-++++++++++TextView text:"Subtraction" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row-group", htmlTag="tbody", tabindex="0"]
-++++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++++TextView text:"10" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++++TextView text:"7" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++++TextView text:"2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++++TextView text:"4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-footer-group", htmlTag="tfoot", tabindex="0"]
-++++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++++TextView text:"12" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++++TextView text:"3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView text:"Table example - focusable thead, tbody, tfoot" textSize:16.0 style:0 bundle:[metadata="[<title>Table example - focusable thead, tbody, tfoot</title>]"] htmlInfo:[{htmlTag="#document"}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}, {border="1"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="thead"}, {display="table-header-group"}, {tabindex="0"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}]
+++++++++++TextView text:"Sum" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}]
+++++++++++TextView text:"Subtraction" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tbody"}, {display="table-row-group"}, {tabindex="0"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++++TextView text:"10" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++++TextView text:"7" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++++TextView text:"2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++++TextView text:"4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tfoot"}, {display="table-footer-group"}, {tabindex="0"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++++TextView text:"12" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++++TextView text:"3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/table-layout-expected-android-assist-data.txt b/content/test/data/accessibility/html/table-layout-expected-android-assist-data.txt
index 17ce65f..45441559 100644
--- a/content/test/data/accessibility/html/table-layout-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/table-layout-expected-android-assist-data.txt
@@ -1,23 +1,23 @@
-WebView text:"Table example #2" textSize:16.00 style:0 bundle:[display="", htmlTag="#document", metadata="[<title>Table example #2</title>]"]
-++View textSize:16.00 style:0 bundle:[display="table", htmlTag="table"]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"5" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"6" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"7" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"8" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"9" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView text:"Table example #2" textSize:16.0 style:0 bundle:[metadata="[<title>Table example #2</title>]"] htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"5" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"6" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"7" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"8" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"9" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/table-presentation-expected-android-assist-data.txt b/content/test/data/accessibility/html/table-presentation-expected-android-assist-data.txt
index 94bec2b..a7efaac3 100644
--- a/content/test/data/accessibility/html/table-presentation-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/table-presentation-expected-android-assist-data.txt
@@ -1,9 +1,9 @@
-WebView text:"Table with role=presentation" textSize:16.00 style:0 bundle:[display="", htmlTag="#document", metadata="[<title>Table with role=presentation</title>]"]
-++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++TextView text:"1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++TextView text:"2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++TextView text:"4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++TextView text:"5" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView text:"Table with role=presentation" textSize:16.0 style:0 bundle:[metadata="[<title>Table with role=presentation</title>]"] htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++TextView text:"1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++TextView text:"2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++TextView text:"4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++TextView text:"5" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/table-simple-2-expected-android-assist-data.txt b/content/test/data/accessibility/html/table-simple-2-expected-android-assist-data.txt
index 17ce65f..45441559 100644
--- a/content/test/data/accessibility/html/table-simple-2-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/table-simple-2-expected-android-assist-data.txt
@@ -1,23 +1,23 @@
-WebView text:"Table example #2" textSize:16.00 style:0 bundle:[display="", htmlTag="#document", metadata="[<title>Table example #2</title>]"]
-++View textSize:16.00 style:0 bundle:[display="table", htmlTag="table"]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"5" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"6" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"7" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"8" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"9" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView text:"Table example #2" textSize:16.0 style:0 bundle:[metadata="[<title>Table example #2</title>]"] htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"5" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"6" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"7" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"8" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"9" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/table-simple-expected-android-assist-data.txt b/content/test/data/accessibility/html/table-simple-expected-android-assist-data.txt
index 7aff80b4..1772364b8 100644
--- a/content/test/data/accessibility/html/table-simple-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/table-simple-expected-android-assist-data.txt
@@ -1,17 +1,17 @@
-WebView text:"Table example" textSize:16.00 style:0 bundle:[display="", htmlTag="#document", metadata="[<title>Table example</title>]"]
-++GridView textSize:16.00 style:0 bundle:[border="1", display="table", htmlTag="table"]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:1 bundle:[display="table-cell", htmlTag="th"]
-++++++++TextView text:"Pair" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:1 bundle:[display="table-cell", htmlTag="th"]
-++++++++TextView text:"Single" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"AB" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"B" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"CD" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"D" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView text:"Table example" textSize:16.0 style:0 bundle:[metadata="[<title>Table example</title>]"] htmlInfo:[{htmlTag="#document"}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}, {border="1"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}]
+++++++++TextView text:"Pair" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}]
+++++++++TextView text:"Single" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"AB" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"B" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"CD" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"D" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/table-spans-expected-android-assist-data.txt b/content/test/data/accessibility/html/table-spans-expected-android-assist-data.txt
index 5d902bc..bf0fbc3 100644
--- a/content/test/data/accessibility/html/table-spans-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/table-spans-expected-android-assist-data.txt
@@ -1,21 +1,21 @@
-WebView text:"Table example with rowspan and colspan" textSize:16.00 style:0 bundle:[display="", htmlTag="#document", metadata="[<title>Table example with rowspan and colspan</title>]"]
-++GridView textSize:16.00 style:0 bundle:[border="1", display="table", htmlTag="table"]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td", rowspan="2"]
-++++++++TextView text:"AD" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[colspan="2", display="table-cell", htmlTag="td"]
-++++++++TextView text:"BC" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[colspan="2", display="table-cell", htmlTag="td"]
-++++++++TextView text:"EF" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++GridView textSize:16.00 style:0 bundle:[border="1", display="table", htmlTag="table"]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td", rowspan="2"]
-++++++++TextView text:"AD" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[colspan="2", display="table-cell", htmlTag="td"]
-++++++++TextView text:"BC" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"EF" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"GH" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView text:"Table example with rowspan and colspan" textSize:16.0 style:0 bundle:[metadata="[<title>Table example with rowspan and colspan</title>]"] htmlInfo:[{htmlTag="#document"}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}, {border="1"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {rowspan="2"}]
+++++++++TextView text:"AD" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {colspan="2"}]
+++++++++TextView text:"BC" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {colspan="2"}]
+++++++++TextView text:"EF" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}, {border="1"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {rowspan="2"}]
+++++++++TextView text:"AD" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}, {colspan="2"}]
+++++++++TextView text:"BC" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"EF" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"GH" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/table-th-colheader-expected-android-assist-data.txt b/content/test/data/accessibility/html/table-th-colheader-expected-android-assist-data.txt
index ecda7a5b..70276e2 100644
--- a/content/test/data/accessibility/html/table-th-colheader-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/table-th-colheader-expected-android-assist-data.txt
@@ -1,12 +1,12 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++GridView textSize:16.00 style:0 bundle:[border="1", display="table", htmlTag="table"]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View text:"Firstname" textSize:16.00 style:1 bundle:[aria-label="Firstname", class="test", display="table-cell", htmlTag="th"]
-++++++++TextView text:"Firstname" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++++View text:"Lastname" textSize:16.00 style:1 bundle:[aria-label="Lastname", display="table-cell", htmlTag="th"]
-++++++++TextView text:"Lastname" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"Jill" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"Smith" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}, {border="1"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View text:"Firstname" textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}, {aria-label="Firstname"}, {class="test"}]
+++++++++TextView text:"Firstname" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View text:"Lastname" textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}, {aria-label="Lastname"}]
+++++++++TextView text:"Lastname" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"Jill" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"Smith" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/table-th-rowheader-expected-android-assist-data.txt b/content/test/data/accessibility/html/table-th-rowheader-expected-android-assist-data.txt
index 4751a98..97ebbc1 100644
--- a/content/test/data/accessibility/html/table-th-rowheader-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/table-th-rowheader-expected-android-assist-data.txt
@@ -1,12 +1,12 @@
-WebView text:"Table example - th rowheader" textSize:16.00 style:0 bundle:[display="", htmlTag="#document", metadata="[<title>Table example - th rowheader</title>]"]
-++GridView textSize:16.00 style:0 bundle:[border="1", display="table", htmlTag="table"]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View text:"Firstname" textSize:16.00 style:1 bundle:[aria-label="Firstname", display="table-cell", htmlTag="th"]
-++++++++TextView text:"Firstname" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"Jill" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View text:"Lastname" textSize:16.00 style:1 bundle:[aria-label="Lastname", display="table-cell", htmlTag="th"]
-++++++++TextView text:"Lastname" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"Smith" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView text:"Table example - th rowheader" textSize:16.0 style:0 bundle:[metadata="[<title>Table example - th rowheader</title>]"] htmlInfo:[{htmlTag="#document"}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}, {border="1"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View text:"Firstname" textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}, {aria-label="Firstname"}]
+++++++++TextView text:"Firstname" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"Jill" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View text:"Lastname" textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}, {aria-label="Lastname"}]
+++++++++TextView text:"Lastname" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"Smith" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/table-thead-tbody-tfoot-expected-android-assist-data.txt b/content/test/data/accessibility/html/table-thead-tbody-tfoot-expected-android-assist-data.txt
index b58b409..380ac74 100644
--- a/content/test/data/accessibility/html/table-thead-tbody-tfoot-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/table-thead-tbody-tfoot-expected-android-assist-data.txt
@@ -1,22 +1,22 @@
-WebView text:"Table example - thead, tbody, tfoot" textSize:16.00 style:0 bundle:[display="", htmlTag="#document", metadata="[<title>Table example - thead, tbody, tfoot</title>]"]
-++GridView textSize:16.00 style:0 bundle:[border="1", display="table", htmlTag="table"]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:1 bundle:[display="table-cell", htmlTag="th"]
-++++++++TextView text:"Sum" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:1 bundle:[display="table-cell", htmlTag="th"]
-++++++++TextView text:"Subtraction" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"10" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"7" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"4" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="table-row", htmlTag="tr"]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"12" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="table-cell", htmlTag="td"]
-++++++++TextView text:"3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView text:"Table example - thead, tbody, tfoot" textSize:16.0 style:0 bundle:[metadata="[<title>Table example - thead, tbody, tfoot</title>]"] htmlInfo:[{htmlTag="#document"}, {display=""}]
+++GridView textSize:16.0 style:0 htmlInfo:[{htmlTag="table"}, {display="table"}, {border="1"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}]
+++++++++TextView text:"Sum" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:1 htmlInfo:[{htmlTag="th"}, {display="table-cell"}]
+++++++++TextView text:"Subtraction" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"10" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"7" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"4" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="tr"}, {display="table-row"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"12" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="td"}, {display="table-cell"}]
+++++++++TextView text:"3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/text-align-expected-android-assist-data.txt b/content/test/data/accessibility/html/text-align-expected-android-assist-data.txt
index 91704a8f..92952df9 100644
--- a/content/test/data/accessibility/html/text-align-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/text-align-expected-android-assist-data.txt
@@ -1,23 +1,23 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", style="text-align: left"]
-++++TextView text:"Left-aligned text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", style="text-align: right"]
-++++TextView text:"Right-aligned text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", style="text-align: center"]
-++++TextView text:"Centered text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", style="text-align: justify"]
-++++TextView text:"Justified text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", style="text-align: -webkit-left"]
-++++TextView text:"Webkit left-aligned text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", style="text-align: -webkit-right"]
-++++TextView text:"Webkit right-aligned text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", style="text-align: -webkit-center"]
-++++TextView text:"Webkit centered text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", style="text-align: start"]
-++++TextView text:"Start-aligned text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", style="text-align: end"]
-++++TextView text:"End-aligned text" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++TextView text:"No text alignment specified" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", style="text-align: none"]
-++++TextView text:"Invalid text alignment" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="text-align: left"}]
+++++TextView text:"Left-aligned text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="text-align: right"}]
+++++TextView text:"Right-aligned text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="text-align: center"}]
+++++TextView text:"Centered text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="text-align: justify"}]
+++++TextView text:"Justified text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="text-align: -webkit-left"}]
+++++TextView text:"Webkit left-aligned text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="text-align: -webkit-right"}]
+++++TextView text:"Webkit right-aligned text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="text-align: -webkit-center"}]
+++++TextView text:"Webkit centered text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="text-align: start"}]
+++++TextView text:"Start-aligned text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="text-align: end"}]
+++++TextView text:"End-aligned text" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++TextView text:"No text alignment specified" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="text-align: none"}]
+++++TextView text:"Invalid text alignment" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/text-colors-and-styles-expected-android-assist-data.txt b/content/test/data/accessibility/html/text-colors-and-styles-expected-android-assist-data.txt
index 50a4dc5..dbee738 100644
--- a/content/test/data/accessibility/html/text-colors-and-styles-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/text-colors-and-styles-expected-android-assist-data.txt
@@ -1,12 +1,12 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 fgColor:-15584170 bgColor:-5517841 bundle:[display="block", htmlTag="p", style="color:#123456;background:#abcdef"]
-++++TextView text:"color" textSize:16.00 style:0 fgColor:-15584170 bgColor:-5517841 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:1 bundle:[display="block", htmlTag="h1"]
-++++TextView text:"text size" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++View textSize:12.00 style:3 bundle:[display="block", htmlTag="h2"]
-++++TextView text:"text style" textSize:12.00 style:3 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="p"]
-++++TextView text:"strong" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
-++TextView text:"italic" textSize:16.00 style:2 bundle:[display="", htmlTag=""]
-++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++TextView text:"bold" textSize:16.00 style:1 bundle:[display="", htmlTag=""]
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 fgColor:-15584170 bgColor:-5517841 htmlInfo:[{htmlTag="p"}, {display="block"}, {style="color:#123456;background:#abcdef"}]
+++++TextView text:"color" textSize:16.0 style:0 fgColor:-15584170 bgColor:-5517841 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:1 htmlInfo:[{htmlTag="h1"}, {display="block"}]
+++++TextView text:"text size" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:12.0 style:3 htmlInfo:[{htmlTag="h2"}, {display="block"}]
+++++TextView text:"text style" textSize:12.0 style:3 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="p"}, {display="block"}]
+++++TextView text:"strong" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
+++TextView text:"italic" textSize:16.0 style:2 htmlInfo:[{htmlTag=""}, {display=""}]
+++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++TextView text:"bold" textSize:16.0 style:1 htmlInfo:[{htmlTag=""}, {display=""}]
diff --git a/content/test/data/accessibility/html/text-indent-expected-android-assist-data.txt b/content/test/data/accessibility/html/text-indent-expected-android-assist-data.txt
index 7b7d1f1..676002dd 100644
--- a/content/test/data/accessibility/html/text-indent-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/text-indent-expected-android-assist-data.txt
@@ -1,15 +1,15 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", style="text-indent: 50px"]
-++++TextView text:"Text indent 50px" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", style="text-indent: -50px"]
-++++TextView text:"Text indent -50px" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", style="text-indent: 0px"]
-++++TextView text:"Text indent 0px" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", style="text-indent: initial"]
-++++TextView text:"Text indent initial" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", style="text-indent: inherit"]
-++++TextView text:"Text indent inherit" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div"]
-++++TextView text:"No text indent specified" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="div", style="text-indent: blah"]
-++++TextView text:"Invalid text indent" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="text-indent: 50px"}]
+++++TextView text:"Text indent 50px" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="text-indent: -50px"}]
+++++TextView text:"Text indent -50px" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="text-indent: 0px"}]
+++++TextView text:"Text indent 0px" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="text-indent: initial"}]
+++++TextView text:"Text indent initial" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="text-indent: inherit"}]
+++++TextView text:"Text indent inherit" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++TextView text:"No text indent specified" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {style="text-indent: blah"}]
+++++TextView text:"Invalid text indent" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/textarea-expected-android-assist-data.txt b/content/test/data/accessibility/html/textarea-expected-android-assist-data.txt
index 67f62f61..3f35658f 100644
--- a/content/test/data/accessibility/html/textarea-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/textarea-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++EditText text:"The \ntextarea tag  defines a multi-line text input control.\n" textSize:13.33 style:0 bundle:[display="inline-block", htmlTag="textarea", rows="4", style="font-family: monospace; width: 50ch"]
-++++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div"]
-++++++++TextView text:"The \ntextarea tag  defines a multi-line text input control.\n" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++++++++View text:"\n" textSize:13.33 style:0 bundle:[display="", htmlTag="br"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++EditText text:"The \ntextarea tag  defines a multi-line text input control.\n" textSize:13.3 style:0 htmlInfo:[{htmlTag="textarea"}, {display="inline-block"}, {rows="4"}, {style="font-family: monospace; width: 50ch"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++++++TextView text:"The \ntextarea tag  defines a multi-line text input control.\n" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View text:"\n" textSize:13.3 style:0 htmlInfo:[{htmlTag="br"}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/textarea-read-only-expected-android-assist-data.txt b/content/test/data/accessibility/html/textarea-read-only-expected-android-assist-data.txt
index 23a8330c..3f67ba2 100644
--- a/content/test/data/accessibility/html/textarea-read-only-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/textarea-read-only-expected-android-assist-data.txt
@@ -1,6 +1,6 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++EditText text:"The textarea tag defines a multi-line text input control.\n" textSize:13.33 style:0 bundle:[cols="50", display="inline-block", htmlTag="textarea", readonly="", rows="4", style="font-family: monospace"]
-++++++View textSize:13.33 style:0 bundle:[display="block", htmlTag="div"]
-++++++++TextView text:"The textarea tag defines a multi-line text input control.\n" textSize:13.33 style:0 bundle:[display="", htmlTag=""]
-++++++++View text:"\n" textSize:13.33 style:0 bundle:[display="", htmlTag="br"]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++EditText text:"The textarea tag defines a multi-line text input control.\n" textSize:13.3 style:0 htmlInfo:[{htmlTag="textarea"}, {display="inline-block"}, {cols="50"}, {readonly=""}, {rows="4"}, {style="font-family: monospace"}]
+++++++View textSize:13.3 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}]
+++++++++TextView text:"The textarea tag defines a multi-line text input control.\n" textSize:13.3 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++++View text:"\n" textSize:13.3 style:0 htmlInfo:[{htmlTag="br"}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/time-expected-android-assist-data.txt b/content/test/data/accessibility/html/time-expected-android-assist-data.txt
index 0a8d4baf..33e486cb 100644
--- a/content/test/data/accessibility/html/time-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/time-expected-android-assist-data.txt
@@ -1,7 +1,7 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++View textSize:16.00 style:0 bundle:[display="inline", htmlTag="time"]
-++++++TextView text:"10:00" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:" " textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[datetime="2015-02-14 20:00", display="inline", htmlTag="time"]
-++++++TextView text:"Valentines day" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="time"}, {display="inline"}]
+++++++TextView text:"10:00" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:" " textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="time"}, {display="inline"}, {datetime="2015-02-14 20:00"}]
+++++++TextView text:"Valentines day" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/ul-contenteditable-expected-android-assist-data.txt b/content/test/data/accessibility/html/ul-contenteditable-expected-android-assist-data.txt
index 2e709ca..39cb622 100644
--- a/content/test/data/accessibility/html/ul-contenteditable-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/ul-contenteditable-expected-android-assist-data.txt
@@ -1,9 +1,9 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++EditText text:"• Hello\n• Bye" textSize:16.00 style:0 bundle:[contenteditable="true", display="block", htmlTag="div", role="textbox"]
-++++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul"]
-++++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++++View text:"• " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++++TextView text:"Hello" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++++View text:"• " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++++TextView text:"Bye" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++EditText text:"• Hello\n• Bye" textSize:16.0 style:0 htmlInfo:[{htmlTag="div"}, {display="block"}, {contenteditable="true"}, {role="textbox"}]
+++++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++++View text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++++TextView text:"Hello" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++++View text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++++TextView text:"Bye" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/ul-expected-android-assist-data.txt b/content/test/data/accessibility/html/ul-expected-android-assist-data.txt
index 088f8f7..f2529ae 100644
--- a/content/test/data/accessibility/html/ul-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/ul-expected-android-assist-data.txt
@@ -1,11 +1,11 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++ListView textSize:16.00 style:0 bundle:[display="block", htmlTag="ul"]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"• " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"Item 1" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"• " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"Item 2" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++View textSize:16.00 style:0 bundle:[display="list-item", htmlTag="li"]
-++++++View text:"• " textSize:16.00 style:0 bundle:[display="inline-block", htmlTag="::marker"]
-++++++TextView text:"Item 3" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++ListView textSize:16.0 style:0 htmlInfo:[{htmlTag="ul"}, {display="block"}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"Item 1" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"Item 2" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++View textSize:16.0 style:0 htmlInfo:[{htmlTag="li"}, {display="list-item"}]
+++++++View text:"• " textSize:16.0 style:0 htmlInfo:[{htmlTag="::marker"}, {display="inline-block"}]
+++++++TextView text:"Item 3" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/var-expected-android-assist-data.txt b/content/test/data/accessibility/html/var-expected-android-assist-data.txt
index 71c605a..2738bbc 100644
--- a/content/test/data/accessibility/html/var-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/var-expected-android-assist-data.txt
@@ -1,3 +1,3 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++TextView text:"Variable" textSize:16.00 style:2 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++TextView text:"Variable" textSize:16.0 style:2 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/wbr-expected-android-assist-data.txt b/content/test/data/accessibility/html/wbr-expected-android-assist-data.txt
index 923f912..ee652f4 100644
--- a/content/test/data/accessibility/html/wbr-expected-android-assist-data.txt
+++ b/content/test/data/accessibility/html/wbr-expected-android-assist-data.txt
@@ -1,5 +1,5 @@
-WebView textSize:16.00 style:0 bundle:[display="", htmlTag="#document"]
-++View textSize:16.00 style:0 bundle:[display="block", htmlTag="body"]
-++++TextView text:"Supercali" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"fragilistic" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
-++++TextView text:"expialidocious" textSize:16.00 style:0 bundle:[display="", htmlTag=""]
\ No newline at end of file
+WebView textSize:16.0 style:0 htmlInfo:[{htmlTag="#document"}, {display=""}]
+++View textSize:16.0 style:0 htmlInfo:[{htmlTag="body"}, {display="block"}]
+++++TextView text:"Supercali" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"fragilistic" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
+++++TextView text:"expialidocious" textSize:16.0 style:0 htmlInfo:[{htmlTag=""}, {display=""}]
\ No newline at end of file
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_integration_test_base.py b/content/test/gpu/gpu_tests/webgl_conformance_integration_test_base.py
index 18114df..d3394cdd 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_integration_test_base.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_integration_test_base.py
@@ -222,7 +222,8 @@
   @classmethod
   def _RestoreBrowserEnvironment(cls) -> None:
     if cls._original_environ is not None:
-      os.environ = cls._original_environ.copy()
+      os.environ.clear()
+      os.environ.update(cls._original_environ)
     super()._RestoreBrowserEnvironment()
 
   def _ShouldForceRetryOnFailureFirstTest(self) -> bool:
diff --git a/content/test/gpu/gpu_tests/webgpu_cts_integration_test_base.py b/content/test/gpu/gpu_tests/webgpu_cts_integration_test_base.py
index 1f4389a..6634bcc 100644
--- a/content/test/gpu/gpu_tests/webgpu_cts_integration_test_base.py
+++ b/content/test/gpu/gpu_tests/webgpu_cts_integration_test_base.py
@@ -252,7 +252,8 @@
   @classmethod
   def _RestoreBrowserEnvironment(cls) -> None:
     if cls._original_environ is not None:
-      os.environ = cls._original_environ.copy()
+      os.environ.clear()
+      os.environ.update(cls._original_environ)
     super()._RestoreBrowserEnvironment()
 
   @classmethod
diff --git a/docs/website b/docs/website
index b62ff6e..504421a 160000
--- a/docs/website
+++ b/docs/website
@@ -1 +1 @@
-Subproject commit b62ff6eb4a7f802e6bf27bb9e89248c94f095579
+Subproject commit 504421a2e612c9042411ae65e24d7a7682dfdbe2
diff --git a/gpu/command_buffer/service/dawn_instance.cc b/gpu/command_buffer/service/dawn_instance.cc
index 14c9715..16ba2ae 100644
--- a/gpu/command_buffer/service/dawn_instance.cc
+++ b/gpu/command_buffer/service/dawn_instance.cc
@@ -9,7 +9,9 @@
 #include "base/base_paths.h"
 #include "base/files/file_path.h"
 #include "base/path_service.h"
+#include "base/strings/string_split.h"
 #include "build/buildflag.h"
+#include "gpu/config/gpu_finch_features.h"
 #include "gpu/config/gpu_preferences.h"
 
 #if BUILDFLAG(IS_MAC)
@@ -24,6 +26,56 @@
     dawn::platform::Platform* platform,
     const GpuPreferences& gpu_preferences,
     SafetyLevel safety) {
+  // Populate the WGSL blocklist based on the Finch feature.
+  std::vector<std::string> wgsl_unsafe_features_owned;
+  std::vector<const char*> wgsl_unsafe_features;
+
+  if (safety != SafetyLevel::kUnsafe) {
+    wgsl_unsafe_features_owned =
+        base::SplitString(features::kWGSLUnsafeFeatures.Get(), ",",
+                          base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+    wgsl_unsafe_features.reserve(wgsl_unsafe_features_owned.size());
+    for (const auto& f : wgsl_unsafe_features_owned) {
+      wgsl_unsafe_features.push_back(f.c_str());
+    }
+  }
+  wgpu::DawnWGSLBlocklist wgsl_blocklist;
+  wgsl_blocklist.nextInChain = nullptr;
+  wgsl_blocklist.blocklistedFeatureCount = wgsl_unsafe_features.size();
+  wgsl_blocklist.blocklistedFeatures = wgsl_unsafe_features.data();
+
+  // Populate the instance toggles becaused on command line parameters and
+  // safety levels. Toggles which are not instance toggles will be ignored by
+  // the instance.
+  std::vector<const char*> require_instance_enabled_toggles;
+  std::vector<const char*> require_instance_disabled_toggles;
+
+  if (safety == SafetyLevel::kSafeExperimental) {
+    require_instance_enabled_toggles.push_back(
+        "expose_wgsl_experimental_features");
+  } else if (safety == SafetyLevel::kUnsafe) {
+    require_instance_enabled_toggles.push_back("allow_unsafe_apis");
+  }
+
+  for (const std::string& toggles :
+       gpu_preferences.enabled_dawn_features_list) {
+    require_instance_enabled_toggles.push_back(toggles.c_str());
+  }
+  for (const std::string& toggles :
+       gpu_preferences.disabled_dawn_features_list) {
+    require_instance_disabled_toggles.push_back(toggles.c_str());
+  }
+
+  wgpu::DawnTogglesDescriptor dawn_toggle_desc;
+  dawn_toggle_desc.nextInChain = &wgsl_blocklist;
+  dawn_toggle_desc.enabledToggleCount = require_instance_enabled_toggles.size();
+  dawn_toggle_desc.enabledToggles = require_instance_enabled_toggles.data();
+  dawn_toggle_desc.disabledToggleCount =
+      require_instance_disabled_toggles.size();
+  dawn_toggle_desc.disabledToggles = require_instance_disabled_toggles.data();
+
+  // Use DawnInstanceDescriptor to pass in the platform and additional search
+  // paths
   std::string dawn_search_path;
   base::FilePath module_path;
 #if BUILDFLAG(IS_MAC)
@@ -46,41 +98,14 @@
   }
   const char* dawn_search_path_c_str = dawn_search_path.c_str();
 
-  std::vector<const char*> require_instance_enabled_toggles;
-  std::vector<const char*> require_instance_disabled_toggles;
-
-  if (safety == SafetyLevel::kSafeExperimental) {
-    require_instance_enabled_toggles.push_back(
-        "expose_wgsl_experimental_features");
-  } else if (safety == SafetyLevel::kUnsafe) {
-    require_instance_enabled_toggles.push_back("allow_unsafe_apis");
-  }
-
-  // Create instance with all user-required toggles, those which are not
-  // instance toggles will be ignored by Dawn.
-  for (const std::string& toggles :
-       gpu_preferences.enabled_dawn_features_list) {
-    require_instance_enabled_toggles.push_back(toggles.c_str());
-  }
-  for (const std::string& toggles :
-       gpu_preferences.disabled_dawn_features_list) {
-    require_instance_disabled_toggles.push_back(toggles.c_str());
-  }
-
-  wgpu::DawnTogglesDescriptor dawn_toggle_desc;
-  dawn_toggle_desc.enabledToggleCount = require_instance_enabled_toggles.size();
-  dawn_toggle_desc.enabledToggles = require_instance_enabled_toggles.data();
-  dawn_toggle_desc.disabledToggleCount =
-      require_instance_disabled_toggles.size();
-  dawn_toggle_desc.disabledToggles = require_instance_disabled_toggles.data();
-
   dawn::native::DawnInstanceDescriptor dawn_instance_desc;
+  dawn_instance_desc.nextInChain = &dawn_toggle_desc;
   dawn_instance_desc.additionalRuntimeSearchPathsCount =
       dawn_search_path.empty() ? 0u : 1u;
   dawn_instance_desc.additionalRuntimeSearchPaths = &dawn_search_path_c_str;
   dawn_instance_desc.platform = platform;
-  dawn_instance_desc.nextInChain = &dawn_toggle_desc;
 
+  // Create the instance with all the previous descriptors chained.
   wgpu::InstanceDescriptor instance_desc;
   instance_desc.nextInChain = &dawn_instance_desc;
 
diff --git a/gpu/command_buffer/service/service_utils.cc b/gpu/command_buffer/service/service_utils.cc
index 4a1fcb8..7dd3eb4c 100644
--- a/gpu/command_buffer/service/service_utils.cc
+++ b/gpu/command_buffer/service/service_utils.cc
@@ -208,7 +208,12 @@
         base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
   }
   gpu_preferences.gr_context_type = ParseGrContextType(command_line);
-  gpu_preferences.use_vulkan = ParseVulkanImplementationName(command_line);
+  // ParseGrContextType checks Vulkan setting as well, so only parse Vulkan
+  // implementation name if gr_context_type is kVulkan.
+  gpu_preferences.use_vulkan =
+      gpu_preferences.gr_context_type == GrContextType::kVulkan
+          ? ParseVulkanImplementationName(command_line)
+          : VulkanImplementationName::kNone;
 
 #if BUILDFLAG(IS_FUCHSIA)
   // Vulkan Surface is not used on Fuchsia.
diff --git a/gpu/command_buffer/service/shared_image/external_vk_image_backing.cc b/gpu/command_buffer/service/shared_image/external_vk_image_backing.cc
index 806d9c2..0e57691 100644
--- a/gpu/command_buffer/service/shared_image/external_vk_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image/external_vk_image_backing.cc
@@ -18,6 +18,7 @@
 #include "gpu/command_buffer/service/shared_image/external_vk_image_skia_representation.h"
 #include "gpu/command_buffer/service/shared_image/gl_texture_holder.h"
 #include "gpu/command_buffer/service/shared_image/shared_image_format_service_utils.h"
+#include "gpu/command_buffer/service/shared_image/shared_image_gl_utils.h"
 #include "gpu/command_buffer/service/shared_image/skia_gl_image_representation.h"
 #include "gpu/command_buffer/service/skia_utils.h"
 #include "gpu/ipc/common/vulkan_ycbcr_info.h"
@@ -124,13 +125,6 @@
   return true;
 }
 
-bool UseTexStorage2D() {
-  const auto* version_info = gl::g_current_gl_version;
-  const auto& ext = gl::g_current_gl_driver->ext;
-  return ext.b_GL_EXT_texture_storage || ext.b_GL_ARB_texture_storage ||
-         version_info->is_es3 || version_info->IsAtLeastGL(4, 2);
-}
-
 bool UseMinimalUsageFlags(SharedContextState* context_state) {
   return context_state->support_gl_external_object_flags();
 }
@@ -805,7 +799,7 @@
 
   if (use_separate_gl_texture()) {
     DCHECK(!memory_object);
-    if (UseTexStorage2D()) {
+    if (IsTexStorage2DAvailable()) {
       api->glTexStorage2DEXTFn(GL_TEXTURE_2D, 1,
                                format_desc.storage_internal_format,
                                plane_size.width(), plane_size.height());
diff --git a/gpu/command_buffer/service/shared_image/shared_image_gl_utils.cc b/gpu/command_buffer/service/shared_image/shared_image_gl_utils.cc
index afbe504..07f5e58 100644
--- a/gpu/command_buffer/service/shared_image/shared_image_gl_utils.cc
+++ b/gpu/command_buffer/service/shared_image/shared_image_gl_utils.cc
@@ -122,4 +122,11 @@
   return service_id;
 }
 
+bool IsTexStorage2DAvailable() {
+  const auto* version_info = gl::g_current_gl_version;
+  const auto& ext = gl::g_current_gl_driver->ext;
+  return ext.b_GL_EXT_texture_storage || ext.b_GL_ARB_texture_storage ||
+         version_info->is_es3 || version_info->IsAtLeastGL(4, 2);
+}
+
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/shared_image/shared_image_gl_utils.h b/gpu/command_buffer/service/shared_image/shared_image_gl_utils.h
index 11234c6..3cc954ab 100644
--- a/gpu/command_buffer/service/shared_image/shared_image_gl_utils.h
+++ b/gpu/command_buffer/service/shared_image/shared_image_gl_utils.h
@@ -77,6 +77,9 @@
     scoped_refptr<gles2::TexturePassthrough>* passthrough_texture,
     raw_ptr<gles2::Texture>* texture);
 
+// Returns whether `glTexStorage2DEXTFn` is available to call on the GL driver.
+bool IsTexStorage2DAvailable();
+
 }  // namespace gpu
 
 #endif  // GPU_COMMAND_BUFFER_SERVICE_SHARED_IMAGE_SHARED_IMAGE_GL_UTILS_H_
diff --git a/gpu/command_buffer/service/shared_image/shared_image_representation.cc b/gpu/command_buffer/service/shared_image/shared_image_representation.cc
index 7e70855..ce9723c 100644
--- a/gpu/command_buffer/service/shared_image/shared_image_representation.cc
+++ b/gpu/command_buffer/service/shared_image/shared_image_representation.cc
@@ -361,8 +361,7 @@
     AllowUnclearedAccess allow_uncleared,
     bool use_sk_surface) {
   return BeginScopedWriteAccess(
-      /*final_msaa_count=*/1,
-      SkSurfaceProps(/*flags=*/0, kUnknown_SkPixelGeometry), begin_semaphores,
+      /*final_msaa_count=*/1, SkSurfaceProps(), begin_semaphores,
       end_semaphores, allow_uncleared, use_sk_surface);
 }
 
@@ -602,8 +601,7 @@
     AllowUnclearedAccess allow_uncleared,
     bool use_sk_surface) {
   return BeginScopedWriteAccess(
-      /*final_msaa_count=*/1,
-      SkSurfaceProps(/*flags=*/0, kUnknown_SkPixelGeometry), begin_semaphores,
+      /*final_msaa_count=*/1, SkSurfaceProps(), begin_semaphores,
       end_semaphores, allow_uncleared, use_sk_surface);
 }
 
diff --git a/gpu/command_buffer/service/webgpu_decoder_impl.cc b/gpu/command_buffer/service/webgpu_decoder_impl.cc
index 838cb6a3..efc5c1c 100644
--- a/gpu/command_buffer/service/webgpu_decoder_impl.cc
+++ b/gpu/command_buffer/service/webgpu_decoder_impl.cc
@@ -81,15 +81,6 @@
 constexpr wgpu::TextureUsage kAllowedMailboxTextureUsages =
     kAllowedWritableMailboxTextureUsages | kAllowedReadableMailboxTextureUsages;
 
-// List of feature names, delimited by ,
-// The FeatureParam may be overridden via Finch config, or via the command line
-// For example:
-//   --enable-field-trial-config \
-//   --force-fieldtrial-params=WebGPU.Enabled:UnsafeFeatures/timestamp-query%2Cshader-f16
-// Note that the comma should be URL-encoded.
-const base::FeatureParam<std::string> kRuntimeUnsafeFeatures{
-    &features::kWebGPUService, "UnsafeFeatures", ""};
-
 template <typename T1, typename T2>
 void ChainStruct(T1& head, T2* struct_to_chain) {
   DCHECK(struct_to_chain->nextInChain == nullptr);
@@ -1107,7 +1098,7 @@
   require_enabled_toggles_ = gpu_preferences.enabled_dawn_features_list;
   require_disabled_toggles_ = gpu_preferences.disabled_dawn_features_list;
   for (std::string f :
-       base::SplitString(kRuntimeUnsafeFeatures.Get(), ",",
+       base::SplitString(features::kWebGPUUnsafeFeatures.Get(), ",",
                          base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
     runtime_unsafe_features_.insert(std::move(f));
   }
diff --git a/gpu/config/gpu_finch_features.cc b/gpu/config/gpu_finch_features.cc
index 43ba60a..39b439a 100644
--- a/gpu/config/gpu_finch_features.cc
+++ b/gpu/config/gpu_finch_features.cc
@@ -303,6 +303,23 @@
 BASE_FEATURE(kWebGPUBlobCache, "WebGPUBlobCache", WEBGPU_ENABLED);
 #undef WEBGPU_ENABLED
 
+// List of WebGPU feature names, delimited by ,
+// The FeatureParam may be overridden via Finch config, or via the command line
+// For example:
+//   --enable-field-trial-config \
+//   --force-fieldtrial-params=WebGPU.Enabled:UnsafeFeatures/timestamp-query%2Cshader-f16
+// Note that the comma should be URL-encoded.
+const base::FeatureParam<std::string> kWebGPUUnsafeFeatures{
+    &kWebGPUService, "UnsafeFeatures", ""};
+// List of WGSL feature names, delimited by ,
+// The FeatureParam may be overridden via Finch config, or via the command line
+// For example:
+//   --enable-field-trial-config \
+//   --force-fieldtrial-params=WebGPU.Enabled:UnsafeWGSLFeatures/feature_1%2Cfeature_2
+// Note that the comma should be URL-encoded.
+const base::FeatureParam<std::string> kWGSLUnsafeFeatures{
+    &kWebGPUService, "UnsafeWGSLFeatures", ""};
+
 BASE_FEATURE(kWebGPUUseDXC, "WebGPUUseDXC2", base::FEATURE_DISABLED_BY_DEFAULT);
 BASE_FEATURE(kWebGPUUseTintIR,
              "WebGPUUseTintIR",
diff --git a/gpu/config/gpu_finch_features.h b/gpu/config/gpu_finch_features.h
index 11ed91a..9343eef 100644
--- a/gpu/config/gpu_finch_features.h
+++ b/gpu/config/gpu_finch_features.h
@@ -117,6 +117,8 @@
 GPU_EXPORT BASE_DECLARE_FEATURE(kWebGPUBlobCache);
 GPU_EXPORT BASE_DECLARE_FEATURE(kWebGPUUseDXC);
 GPU_EXPORT BASE_DECLARE_FEATURE(kWebGPUUseTintIR);
+GPU_EXPORT extern const base::FeatureParam<std::string> kWebGPUUnsafeFeatures;
+GPU_EXPORT extern const base::FeatureParam<std::string> kWGSLUnsafeFeatures;
 
 GPU_EXPORT BASE_DECLARE_FEATURE(kIncreasedCmdBufferParseSlice);
 
diff --git a/gpu/ipc/service/gpu_init.cc b/gpu/ipc/service/gpu_init.cc
index 28adae6b..73bc1e4 100644
--- a/gpu/ipc/service/gpu_init.cc
+++ b/gpu/ipc/service/gpu_init.cc
@@ -1084,6 +1084,27 @@
       gpu_preferences_.use_vulkan == VulkanImplementationName::kForcedNative;
   bool use_swiftshader = gl_use_swiftshader_ || vulkan_use_swiftshader;
 
+  const base::FeatureParam<std::string> force_enable_patterns(
+      &features::kVulkan, "force_enable_by_gl_renderer", "");
+  forced_native |=
+      MatchGLInfo(gpu_info_.gl_renderer, force_enable_patterns.Get());
+
+  const base::FeatureParam<std::string> disable_by_renderer(
+      &features::kVulkan, "disable_by_gl_renderer", "");
+  bool disabled = MatchGLInfo(gpu_info_.gl_renderer, disable_by_renderer.Get());
+  const base::FeatureParam<std::string> disable_by_driver(
+      &features::kVulkan, "disable_by_gl_driver", "");
+  disabled |=
+      MatchGLInfo(gpu_info_.gpu.driver_version, disable_by_driver.Get());
+#if !BUILDFLAG(IS_ANDROID)
+  // For non-Android, check disabling params before Vulkan initialization.
+  // Android disabling params are checked later, because they can be overridden
+  // by |enable_by_device_name| which requires Vulkan to already be initialized.
+  if (!use_swiftshader && !forced_native && disabled) {
+    return false;
+  }
+#endif  // !BUILDFLAG(IS_ANDROID)
+
   vulkan_implementation_ = CreateVulkanImplementation(
       vulkan_use_swiftshader, gpu_preferences_.enable_vulkan_protected_memory);
   if (!vulkan_implementation_ ||
@@ -1102,22 +1123,12 @@
   if (!vulkan_implementation_)
     return false;
 
-  const base::FeatureParam<std::string> force_enable_patterns(
-      &features::kVulkan, "force_enable_by_gl_renderer", "");
-  forced_native |=
-      MatchGLInfo(gpu_info_.gl_renderer, force_enable_patterns.Get());
-
   const base::FeatureParam<std::string> enable_by_device_name(
       &features::kVulkan, "enable_by_device_name", "");
-  const base::FeatureParam<std::string> disable_by_renderer(
-      &features::kVulkan, "disable_by_gl_renderer", "");
-  const base::FeatureParam<std::string> disable_by_driver(
-      &features::kVulkan, "disable_by_gl_driver", "");
   if (!use_swiftshader && !forced_native &&
       !CheckVulkanCompatibilities(
           vulkan_implementation_->GetVulkanInstance()->vulkan_info(), gpu_info_,
-          enable_by_device_name.Get(), disable_by_renderer.Get(),
-          disable_by_driver.Get())) {
+          enable_by_device_name.Get(), disabled)) {
     vulkan_implementation_.reset();
     return false;
   }
diff --git a/gpu/vulkan/vulkan_util.cc b/gpu/vulkan/vulkan_util.cc
index c30c6b5..d253adc 100644
--- a/gpu/vulkan/vulkan_util.cc
+++ b/gpu/vulkan/vulkan_util.cc
@@ -44,6 +44,8 @@
 
 namespace {
 
+#if BUILDFLAG(IS_ANDROID)
+
 bool IsDeviceBlocked(base::StringPiece field, base::StringPiece block_list) {
   auto disable_patterns = base::SplitString(
       block_list, "|", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
@@ -55,8 +57,6 @@
   return false;
 }
 
-#if BUILDFLAG(IS_ANDROID)
-
 int GetEMUIVersion() {
   const auto* build_info = base::android::BuildInfo::GetInstance();
   base::StringPiece manufacturer(build_info->manufacturer());
@@ -411,8 +411,7 @@
 bool CheckVulkanCompatibilities(const VulkanInfo& vulkan_info,
                                 const GPUInfo& gpu_info,
                                 const std::string& enable_by_device_name,
-                                const std::string& disable_by_renderer,
-                                const std::string& disable_by_driver) {
+                                bool disabled) {
 // Android uses AHB and SyncFD for interop. They are imported into GL with other
 // API.
 #if !BUILDFLAG(IS_ANDROID)
@@ -426,11 +425,7 @@
   constexpr char kMemoryObjectExtension[] = "GL_EXT_memory_object_fd";
   constexpr char kSemaphoreExtension[] = "GL_EXT_semaphore_fd";
 #endif
-  if (IsDeviceBlocked(gpu_info.gl_renderer, disable_by_renderer)) {
-    return false;
-  }
-
-  if (IsDeviceBlocked(gpu_info.gpu.driver_version, disable_by_driver)) {
+  if (disabled) {
     return false;
   }
 
@@ -471,11 +466,7 @@
       return true;
   }
 
-  if (IsDeviceBlocked(gpu_info.gl_renderer, disable_by_renderer)) {
-    return false;
-  }
-
-  if (IsDeviceBlocked(gpu_info.gpu.driver_version, disable_by_driver)) {
+  if (disabled) {
     return false;
   }
 
@@ -532,11 +523,6 @@
     return false;
   }
 
-  // Canvas not working on NVidia shield https://crbug.com/1508791
-  if (device_info.properties.vendorID == kVendorNvidia) {
-    return false;
-  }
-
   return true;
 #endif  // BUILDFLAG(IS_ANDROID)
 }
diff --git a/gpu/vulkan/vulkan_util.h b/gpu/vulkan/vulkan_util.h
index 0a599887..b5012d6 100644
--- a/gpu/vulkan/vulkan_util.h
+++ b/gpu/vulkan/vulkan_util.h
@@ -20,12 +20,11 @@
 
 namespace gpu {
 
-inline constexpr uint32_t kVendorARM = 0x13b5;
-inline constexpr uint32_t kVendorQualcomm = 0x5143;
-inline constexpr uint32_t kVendorImagination = 0x1010;
-inline constexpr uint32_t kVendorGoogle = 0x1AE0;
-inline constexpr uint32_t kDeviceSwiftShader = 0xC0DE;
-inline constexpr uint32_t kVendorNvidia = 0x10DE;
+constexpr uint32_t kVendorARM = 0x13b5;
+constexpr uint32_t kVendorQualcomm = 0x5143;
+constexpr uint32_t kVendorImagination = 0x1010;
+constexpr uint32_t kVendorGoogle = 0x1AE0;
+constexpr uint32_t kDeviceSwiftShader = 0xC0DE;
 
 struct GPUInfo;
 class VulkanInfo;
@@ -113,8 +112,7 @@
 bool CheckVulkanCompatibilities(const VulkanInfo& vulkan_info,
                                 const GPUInfo& gpu_info,
                                 const std::string& enable_by_device_name,
-                                const std::string& disable_by_renderer,
-                                const std::string& disable_by_driver);
+                                bool disabled);
 
 COMPONENT_EXPORT(VULKAN)
 VkImageLayout GLImageLayoutToVkImageLayout(uint32_t layout);
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 60c9fca..8ae3d24b 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -3177,6 +3177,9 @@
       <message name="IDS_IOS_PASSWORD_SHARING_CANCELLED_TITLE" desc="Title text on the sharing status view when the sharing was cancelled. [iOS only]">
         Password Was Not Shared
       </message>
+      <message name="IDS_IOS_PASSWORD_SHARING_ENTERPRISE_POLICY_DISABLED_MESSAGE" desc="Text displayed on the password sharing popover explaining that the feature is disabled by the enterprise administrator. [iOS only]">
+        Password sharing is disabled by your administrator.
+      </message>
       <message name="IDS_IOS_PASSWORD_SHARING_FAMILY_PICKER_BACK_BUTTON" desc="Button text for the navigation back action in the family picker view in the password sharing flow. [iOS only]">
         Back
       </message>
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_PASSWORD_SHARING_ENTERPRISE_POLICY_DISABLED_MESSAGE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_PASSWORD_SHARING_ENTERPRISE_POLICY_DISABLED_MESSAGE.png.sha1
new file mode 100644
index 0000000..635aa89e
--- /dev/null
+++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_PASSWORD_SHARING_ENTERPRISE_POLICY_DISABLED_MESSAGE.png.sha1
@@ -0,0 +1 @@
+d2460f3538b96095230b31a1efefbf58ad3278fc
\ No newline at end of file
diff --git a/ios/chrome/browser/DEPS b/ios/chrome/browser/DEPS
index 97920cc3..dcf497a 100644
--- a/ios/chrome/browser/DEPS
+++ b/ios/chrome/browser/DEPS
@@ -13,7 +13,6 @@
   "+components/commerce/ios",
   "+components/component_updater",
   "+components/content_settings/core",
-  "+components/cookie_config",
   "+components/country_codes",
   "+components/crash/core/app",
   "+components/crash/core/browser",
diff --git a/ios/chrome/browser/browser_state/model/BUILD.gn b/ios/chrome/browser/browser_state/model/BUILD.gn
index e6693891..f5cfb439 100644
--- a/ios/chrome/browser/browser_state/model/BUILD.gn
+++ b/ios/chrome/browser/browser_state/model/BUILD.gn
@@ -50,7 +50,6 @@
     "//components/browser_sync",
     "//components/content_settings/core/browser",
     "//components/content_settings/core/common",
-    "//components/cookie_config",
     "//components/invalidation/impl",
     "//components/keyed_service/ios",
     "//components/metrics",
diff --git a/ios/chrome/browser/browser_state/model/chrome_browser_state_impl_io_data.mm b/ios/chrome/browser/browser_state/model/chrome_browser_state_impl_io_data.mm
index e6bd337..6d7cadc 100644
--- a/ios/chrome/browser/browser_state/model/chrome_browser_state_impl_io_data.mm
+++ b/ios/chrome/browser/browser_state/model/chrome_browser_state_impl_io_data.mm
@@ -14,7 +14,6 @@
 #import "base/functional/callback.h"
 #import "base/task/sequenced_task_runner.h"
 #import "base/task/thread_pool.h"
-#import "components/cookie_config/cookie_store_util.h"
 #import "components/net_log/chrome_net_log.h"
 #import "components/prefs/json_pref_store.h"
 #import "components/prefs/pref_filter.h"
@@ -173,8 +172,7 @@
   cookie_util::CookieStoreConfig ios_cookie_config(
       lazy_params_->cookie_path,
       cookie_util::CookieStoreConfig::RESTORED_SESSION_COOKIES,
-      cookie_util::CookieStoreConfig::COOKIE_STORE_IOS,
-      cookie_config::GetCookieCryptoDelegate());
+      cookie_util::CookieStoreConfig::COOKIE_STORE_IOS);
   auto cookie_store = cookie_util::CreateCookieStore(
       ios_cookie_config, std::move(profile_params->system_cookie_store),
       io_thread->net_log());
diff --git a/ios/chrome/browser/browser_state/model/off_the_record_chrome_browser_state_io_data.mm b/ios/chrome/browser/browser_state/model/off_the_record_chrome_browser_state_io_data.mm
index 01ac545..b20d661 100644
--- a/ios/chrome/browser/browser_state/model/off_the_record_chrome_browser_state_io_data.mm
+++ b/ios/chrome/browser/browser_state/model/off_the_record_chrome_browser_state_io_data.mm
@@ -147,7 +147,7 @@
       cookie_util::CookieStoreConfig(
           cookie_path_,
           cookie_util::CookieStoreConfig::RESTORED_SESSION_COOKIES,
-          cookie_util::CookieStoreConfig::COOKIE_STORE_IOS, nullptr),
+          cookie_util::CookieStoreConfig::COOKIE_STORE_IOS),
       std::move(profile_params->system_cookie_store), io_thread->net_log()));
 
   net::URLRequestContextBuilder::HttpCacheParams cache_params;
diff --git a/ios/chrome/browser/metrics/model/web_state_list_metrics_browser_agent.mm b/ios/chrome/browser/metrics/model/web_state_list_metrics_browser_agent.mm
index 1f8e81c..4f81b6f 100644
--- a/ios/chrome/browser/metrics/model/web_state_list_metrics_browser_agent.mm
+++ b/ios/chrome/browser/metrics/model/web_state_list_metrics_browser_agent.mm
@@ -162,6 +162,16 @@
   }
   base::UmaHistogramBoolean("Tab.HasThemeColor",
                             web_state->GetThemeColor() != nil);
+  // By default the underpage color is white. Only consider color as custom if
+  // it is not white.
+  CGFloat red = 1;
+  CGFloat green = 1;
+  CGFloat blue = 1;
+  CGFloat alpha = 1;
+  UIColor* color = web_state->GetUnderPageBackgroundColor();
+  [color getRed:&red green:&green blue:&blue alpha:&alpha];
+  BOOL isWhite = red > 0.999 && green > 0.999 && blue > 0.999 && alpha > 0.99;
+  base::UmaHistogramBoolean("Tab.HasCustomUnderPageBackgroundColor", isWhite);
 }
 
 #pragma mark - BrowserObserver
diff --git a/ios/chrome/browser/policy/model/configuration_policy_handler_list_factory.mm b/ios/chrome/browser/policy/model/configuration_policy_handler_list_factory.mm
index 3dcd6ca4..495e8dc 100644
--- a/ios/chrome/browser/policy/model/configuration_policy_handler_list_factory.mm
+++ b/ios/chrome/browser/policy/model/configuration_policy_handler_list_factory.mm
@@ -138,6 +138,9 @@
   { policy::key::kParcelTrackingEnabled,
     prefs::kIosParcelTrackingPolicyEnabled,
     base::Value::Type::BOOLEAN },
+  { policy::key::kInsecureFormsWarningsEnabled,
+    prefs::kInsecureFormWarningsEnabled,
+    base::Value::Type::BOOLEAN },
 };
 // clang-format on
 
diff --git a/ios/chrome/browser/shared/model/prefs/browser_prefs.mm b/ios/chrome/browser/shared/model/prefs/browser_prefs.mm
index a9a6185..fef75e5 100644
--- a/ios/chrome/browser/shared/model/prefs/browser_prefs.mm
+++ b/ios/chrome/browser/shared/model/prefs/browser_prefs.mm
@@ -677,6 +677,8 @@
   registry->RegisterTimePref(prefs::kNotificationsPromoLastShown, base::Time());
   registry->RegisterIntegerPref(prefs::kNotificationsPromoTimesShown, 0);
   registry->RegisterIntegerPref(prefs::kNotificationsPromoTimesDismissed, 0);
+
+  registry->RegisterBooleanPref(prefs::kInsecureFormWarningsEnabled, true);
 }
 
 // This method should be periodically pruned of year+ old migrations.
diff --git a/ios/chrome/browser/shared/model/prefs/pref_names.cc b/ios/chrome/browser/shared/model/prefs/pref_names.cc
index 3060fb1d..4b9a12c4 100644
--- a/ios/chrome/browser/shared/model/prefs/pref_names.cc
+++ b/ios/chrome/browser/shared/model/prefs/pref_names.cc
@@ -495,4 +495,7 @@
 const char kNotificationsPromoTimesDismissed[] =
     "ios.content_notifications.promo_times_dismissed";
 
+const char kInsecureFormWarningsEnabled[] =
+    "ios.insecure_form_warnings_enabled";
+
 }  // namespace prefs
diff --git a/ios/chrome/browser/shared/model/prefs/pref_names.h b/ios/chrome/browser/shared/model/prefs/pref_names.h
index da94ffd..f49fae28 100644
--- a/ios/chrome/browser/shared/model/prefs/pref_names.h
+++ b/ios/chrome/browser/shared/model/prefs/pref_names.h
@@ -137,6 +137,8 @@
 extern const char kNotificationsPromoTimesShown[];
 extern const char kNotificationsPromoTimesDismissed[];
 
+extern const char kInsecureFormWarningsEnabled[];
+
 }  // namespace prefs
 
 #endif  // IOS_CHROME_BROWSER_PREFS_PREF_NAMES_H_
diff --git a/ios/chrome/browser/ssl/model/BUILD.gn b/ios/chrome/browser/ssl/model/BUILD.gn
index 3b40d3f..9c213c8f 100644
--- a/ios/chrome/browser/ssl/model/BUILD.gn
+++ b/ios/chrome/browser/ssl/model/BUILD.gn
@@ -109,9 +109,12 @@
 
   deps = [
     ":eg_test_support+eg2",
+    "//components/policy:policy_code_generate",
     "//components/security_interstitials/core",
     "//components/strings",
     "//ios/chrome/browser/overlays/model/public/web_content_area:constants",
+    "//ios/chrome/browser/policy/model:eg_test_support+eg2",
+    "//ios/chrome/browser/shared/model/prefs:pref_names",
     "//ios/chrome/test:eg_test_support+eg2",
     "//ios/chrome/test/earl_grey:eg_test_support+eg2",
     "//ios/components/security_interstitials/https_only_mode:feature",
diff --git a/ios/chrome/browser/ssl/model/insecure_form_warning_egtest.mm b/ios/chrome/browser/ssl/model/insecure_form_warning_egtest.mm
index 862e44b..19b0f99 100644
--- a/ios/chrome/browser/ssl/model/insecure_form_warning_egtest.mm
+++ b/ios/chrome/browser/ssl/model/insecure_form_warning_egtest.mm
@@ -12,8 +12,11 @@
 #import "base/strings/string_util.h"
 #import "base/strings/stringprintf.h"
 #import "base/test/ios/wait_util.h"
+#import "components/policy/policy_constants.h"
 #import "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/overlays/model/public/web_content_area/alert_constants.h"
+#import "ios/chrome/browser/policy/model/policy_earl_grey_utils.h"
+#import "ios/chrome/browser/shared/model/prefs/pref_names.h"
 #import "ios/chrome/browser/ssl/model/insecure_form_warning_app_interface.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
 #import "ios/chrome/test/earl_grey/chrome_matchers.h"
@@ -87,6 +90,8 @@
 - (void)tearDown {
   [InsecureFormWarningAppInterface setInsecureFormPortsForTesting:0
                                             portTreatedAsInsecure:0];
+  policy_test_utils::ClearPolicies();
+
   [super tearDown];
 }
 
@@ -103,14 +108,7 @@
   return config;
 }
 
-#pragma mark - Tests
-
-// Tests that posting from HTTP to HTTP doesn't show a warning.
-- (void)testHttpToHttpFormSubmit {
-  std::string pageURLString =
-      "/insecure_form.html?" + self.testServer->GetURL("/echo").spec();
-
-  const GURL pageURL = self.testServer->GetURL(pageURLString);
+- (void)submitFormAndExpectNoWarning:(const GURL&)pageURL {
   [ChromeEarlGrey loadURL:pageURL];
   [ChromeEarlGrey
       waitForWebStateContainingText:"Insecure form ready to submit"];
@@ -121,13 +119,24 @@
       waitForWebStateContainingText:"username=testuser&password=testpassword"];
 }
 
+#pragma mark - Tests
+
+// Tests that posting from HTTP to HTTP doesn't show a warning.
+- (void)testHttpToHttpFormSubmit {
+  std::string URLString =
+      "/insecure_form.html?" + self.testServer->GetURL("/echo").spec();
+  const GURL HTTPToHTTPFormURL = self.testServer->GetURL(URLString);
+  [self submitFormAndExpectNoWarning:HTTPToHTTPFormURL];
+}
+
 // Tests that posting from HTTPS to HTTP shows a warning and tapping cancel
 // doesn't send post data.
 - (void)testInsecureFormSubmit_Cancel {
-  std::string pageURLString =
+  std::string URLString =
       "/insecure_form.html?" + self.testServer->GetURL("/echo").spec();
-  const GURL pageURL = _fakeHTTPSServer->GetURL(pageURLString);
-  [ChromeEarlGrey loadURL:pageURL];
+  const GURL FakeHTTPSToHTTPFormURL = _fakeHTTPSServer->GetURL(URLString);
+
+  [ChromeEarlGrey loadURL:FakeHTTPSToHTTPFormURL];
   [ChromeEarlGrey
       waitForWebStateContainingText:"Insecure form ready to submit"];
 
@@ -143,10 +152,11 @@
 // Tests that posting from HTTPS to HTTP shows a warning and tapping
 // "Send anyway" sends the post data.
 - (void)testInsecureFormSubmit_SendAnyway {
-  std::string pageURLString =
+  std::string URLString =
       "/insecure_form.html?" + self.testServer->GetURL("/echo").spec();
-  const GURL pageURL = _fakeHTTPSServer->GetURL(pageURLString);
-  [ChromeEarlGrey loadURL:pageURL];
+  const GURL FakeHTTPSToHTTPFormURL = _fakeHTTPSServer->GetURL(URLString);
+
+  [ChromeEarlGrey loadURL:FakeHTTPSToHTTPFormURL];
   [ChromeEarlGrey
       waitForWebStateContainingText:"Insecure form ready to submit"];
 
@@ -162,17 +172,23 @@
 // Tests that posting from HTTPS to HTTP doesn't show a warning when the feature
 // is disabled.
 - (void)testInsecureFormSubmit_FeatureDisabled {
-  std::string pageURLString =
+  std::string URLString =
       "/insecure_form.html?" + self.testServer->GetURL("/echo").spec();
-  const GURL pageURL = _fakeHTTPSServer->GetURL(pageURLString);
-  [ChromeEarlGrey loadURL:pageURL];
-  [ChromeEarlGrey
-      waitForWebStateContainingText:"Insecure form ready to submit"];
+  const GURL FakeHTTPSToHTTPFormURL = _fakeHTTPSServer->GetURL(URLString);
 
-  // Submit the form, should go through without an interstitial.
-  [ChromeEarlGrey tapWebStateElementWithID:@"submit"];
-  [ChromeEarlGrey
-      waitForWebStateContainingText:"username=testuser&password=testpassword"];
+  [self submitFormAndExpectNoWarning:FakeHTTPSToHTTPFormURL];
+}
+
+// Tests that disabling the feature by policy will stop showing a warning.
+- (void)testInsecureFormSubmit_DisabledByPolicy {
+  policy_test_utils::SetPolicy(false,
+                               policy::key::kInsecureFormsWarningsEnabled);
+
+  std::string URLString =
+      "/insecure_form.html?" + self.testServer->GetURL("/echo").spec();
+  const GURL FakeHTTPSToHTTPFormURL = _fakeHTTPSServer->GetURL(URLString);
+
+  [self submitFormAndExpectNoWarning:FakeHTTPSToHTTPFormURL];
 }
 
 @end
diff --git a/ios/chrome/browser/ui/content_suggestions/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/BUILD.gn
index c2e0b1d..3d49a35a 100644
--- a/ios/chrome/browser/ui/content_suggestions/BUILD.gn
+++ b/ios/chrome/browser/ui/content_suggestions/BUILD.gn
@@ -31,8 +31,6 @@
     "content_suggestions_coordinator.h",
     "content_suggestions_coordinator.mm",
     "content_suggestions_delegate.h",
-    "content_suggestions_favicon_mediator.h",
-    "content_suggestions_favicon_mediator.mm",
     "content_suggestions_mediator.h",
     "content_suggestions_mediator.mm",
     "content_suggestions_mediator_util.h",
@@ -205,7 +203,10 @@
 }
 
 source_set("public") {
-  sources = [ "content_suggestions_menu_provider.h" ]
+  sources = [
+    "content_suggestions_image_data_source.h",
+    "content_suggestions_menu_provider.h",
+  ]
 }
 
 source_set("content_suggestions_ui") {
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_consumer.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_consumer.h
index b68cdb10..7e671b1f 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_consumer.h
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_consumer.h
@@ -66,10 +66,6 @@
 - (void)updateShortcutTileConfig:
     (ContentSuggestionsMostVisitedActionItem*)config;
 
-// Indicates to the consumer update the Most Visited tile associated with
-// `config`.
-- (void)updateMostVisitedTileConfig:(ContentSuggestionsMostVisitedItem*)config;
-
 // Indicates to the consumer to set the Magic Stack module order as listed in
 // `order`.
 - (void)setMagicStackOrder:(NSArray<NSNumber*>*)order;
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm
index 2516ce76..8cc5b16 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm
@@ -70,6 +70,7 @@
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_delegate.h"
+#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_image_data_source.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_menu_provider.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_metrics_recorder.h"
@@ -262,6 +263,8 @@
       [[ContentSuggestionsViewController alloc] init];
   self.contentSuggestionsViewController.suggestionCommandHandler =
       self.contentSuggestionsMediator;
+  self.contentSuggestionsViewController.imageDataSource =
+      self.contentSuggestionsMediator;
   self.contentSuggestionsViewController.audience = self;
   self.contentSuggestionsViewController.menuProvider = self;
   self.contentSuggestionsViewController.urlLoadingBrowserAgent =
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_favicon_mediator.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_favicon_mediator.h
deleted file mode 100644
index 65a52f5d..0000000
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_favicon_mediator.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_FAVICON_MEDIATOR_H_
-#define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_FAVICON_MEDIATOR_H_
-
-#import <UIKit/UIKit.h>
-
-#include "components/ntp_tiles/ntp_tile.h"
-
-namespace favicon {
-class LargeIconService;
-}
-
-@protocol ContentSuggestionsCollectionConsumer;
-@protocol ContentSuggestionsConsumer;
-@class ContentSuggestionsMetricsRecorder;
-@class ContentSuggestionsMostVisitedItem;
-@class FaviconAttributesProvider;
-class LargeIconCache;
-
-// Mediator handling the fetching of the favicon for all ContentSuggestions
-// items.
-@interface ContentSuggestionsFaviconMediator : NSObject
-
-// Initializes the mediator with `largeIconService` to fetch the favicon
-// locally.
-- (instancetype)initWithLargeIconService:
-                    (favicon::LargeIconService*)largeIconService
-                          largeIconCache:(LargeIconCache*)largeIconCache
-    NS_DESIGNATED_INITIALIZER;
-
-- (instancetype)init NS_UNAVAILABLE;
-
-@property(nonatomic, weak) id<ContentSuggestionsConsumer> consumer;
-
-// FaviconAttributesProvider to fetch the favicon for the most visited tiles.
-@property(nonatomic, strong, readonly)
-    FaviconAttributesProvider* mostVisitedAttributesProvider;
-
-// Sets the `mostVisitedData` used to log the impression of the tiles.
-- (void)setMostVisitedDataForLogging:
-    (const ntp_tiles::NTPTilesVector&)mostVisitedData;
-
-// Fetches the favicon for this `item`.
-- (void)fetchFaviconForMostVisited:(ContentSuggestionsMostVisitedItem*)item;
-
-// Recorder for content suggestions metrics.
-@property(nonatomic, weak)
-    ContentSuggestionsMetricsRecorder* contentSuggestionsMetricsRecorder;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_FAVICON_MEDIATOR_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_favicon_mediator.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_favicon_mediator.mm
deleted file mode 100644
index be6e832..0000000
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_favicon_mediator.mm
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_favicon_mediator.h"
-
-#import "base/functional/bind.h"
-#import "components/favicon/core/large_icon_service.h"
-#import "ios/chrome/browser/shared/public/features/features.h"
-#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h"
-#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.h"
-#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_consumer.h"
-#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_metrics_recorder.h"
-#import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestions_section_information.h"
-#import "ios/chrome/browser/ui/favicon/favicon_attributes_provider.h"
-#import "ios/chrome/browser/ui/favicon/favicon_attributes_with_payload.h"
-#import "ui/gfx/image/image.h"
-
-namespace {
-
-// Size of the favicon returned by the provider for the most visited items.
-const CGFloat kMostVisitedFaviconSize = 48;
-// Size below which the provider returns a colored tile instead of an image.
-const CGFloat kMostVisitedFaviconMinimalSize = 32;
-const CGFloat kMagicStackMostVisitedFaviconMinimalSize = 18;
-
-}  // namespace
-
-@interface ContentSuggestionsFaviconMediator () {
-  // Most visited data used for logging the tiles impression. The data is
-  // copied when receiving the first non-empty data. This copy is used to make
-  // sure only the data received the first time is logged, and only once.
-  ntp_tiles::NTPTilesVector _mostVisitedDataForLogging;
-}
-
-// Redefined as readwrite
-@property(nonatomic, nullable, strong, readwrite)
-    FaviconAttributesProvider* mostVisitedAttributesProvider;
-
-@end
-
-@implementation ContentSuggestionsFaviconMediator
-
-#pragma mark - Public.
-
-- (instancetype)initWithLargeIconService:
-                    (favicon::LargeIconService*)largeIconService
-                          largeIconCache:(LargeIconCache*)largeIconCache {
-  self = [super init];
-  if (self) {
-    _mostVisitedAttributesProvider = [[FaviconAttributesProvider alloc]
-        initWithFaviconSize:IsMagicStackEnabled() ? kMagicStackFaviconWidth
-                                                  : kMostVisitedFaviconSize
-             minFaviconSize:IsMagicStackEnabled()
-                                ? kMagicStackMostVisitedFaviconMinimalSize
-                                : kMostVisitedFaviconMinimalSize
-           largeIconService:largeIconService];
-    // Set a cache only for the Most Visited provider, as the cache is
-    // overwritten for every new results and the size of the favicon fetched for
-    // the suggestions is much smaller.
-    _mostVisitedAttributesProvider.cache = largeIconCache;
-  }
-  return self;
-}
-
-- (void)setMostVisitedDataForLogging:
-    (const ntp_tiles::NTPTilesVector&)mostVisitedData {
-  DCHECK(_mostVisitedDataForLogging.empty());
-  _mostVisitedDataForLogging = mostVisitedData;
-}
-
-- (void)fetchFaviconForMostVisited:(ContentSuggestionsMostVisitedItem*)item {
-  __weak ContentSuggestionsFaviconMediator* weakSelf = self;
-  __weak ContentSuggestionsMostVisitedItem* weakItem = item;
-
-  void (^completion)(FaviconAttributes*) = ^(FaviconAttributes* attributes) {
-    ContentSuggestionsFaviconMediator* strongSelf = weakSelf;
-    ContentSuggestionsMostVisitedItem* strongItem = weakItem;
-    if (!strongSelf || !strongItem)
-      return;
-
-    strongItem.attributes = attributes;
-    [strongSelf logFaviconFetchedForItem:strongItem];
-    [strongSelf.consumer updateMostVisitedTileConfig:strongItem];
-  };
-
-  [self.mostVisitedAttributesProvider fetchFaviconAttributesForURL:item.URL
-                                                        completion:completion];
-}
-
-
-#pragma mark - Private.
-
-// If it is the first time the favicon corresponding to `URL` has its favicon
-// fetched, its impression is logged.
-// This is called when the favicon is fetched and might not represent a tile
-// impression (for example, if some tiles are not displayed on screen because
-// the screen is too narrow, their favicons are still fetched, and this function
-// is called).
-- (void)logFaviconFetchedForItem:(ContentSuggestionsMostVisitedItem*)item {
-  for (size_t i = 0; i < _mostVisitedDataForLogging.size(); ++i) {
-    ntp_tiles::NTPTile& ntpTile = _mostVisitedDataForLogging[i];
-    if (ntpTile.url == item.URL) {
-      [self.contentSuggestionsMetricsRecorder recordMostVisitedTileShown:item
-                                                                 atIndex:i];
-      // Reset the URL to be sure to log the impression only once.
-      ntpTile.url = GURL();
-      break;
-    }
-  }
-}
-
-@end
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_image_data_source.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_image_data_source.h
new file mode 100644
index 0000000..f5c61a52
--- /dev/null
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_image_data_source.h
@@ -0,0 +1,25 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_IMAGE_DATA_SOURCE_H_
+#define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_IMAGE_DATA_SOURCE_H_
+
+#import <UIKit/UIKit.h>
+
+@class FaviconAttributes;
+class GURL;
+
+using FaviconCompletionHandler = void (^)(FaviconAttributes*);
+
+// Protocol used by content suggests to retrieve favicons.
+@protocol ContentSuggestionsImageDataSource
+
+// Requests the receiver to provide a favicon image for `URL`. A `completion` is
+// called asynchronously with a FaviconAttributes instance if appropriate.
+- (void)fetchFaviconForURL:(const GURL&)URL
+                completion:(FaviconCompletionHandler)completion;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_IMAGE_DATA_SOURCE_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.h
index 9d65ef78..6a167d3d 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.h
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.h
@@ -13,6 +13,7 @@
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_gesture_commands.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_commands.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_consumer.h"
+#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_image_data_source.h"
 #import "ios/chrome/browser/ui/start_surface/start_surface_recent_tab_removal_observer_bridge.h"
 
 namespace commerce {
@@ -63,6 +64,7 @@
 // Mediator for ContentSuggestions.
 @interface ContentSuggestionsMediator
     : NSObject <ContentSuggestionsCommands,
+                ContentSuggestionsImageDataSource,
                 ContentSuggestionsGestureCommands,
                 StartSurfaceRecentTabObserving>
 
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
index a7234da..f312a05d 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
@@ -96,7 +96,6 @@
 #import "ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_delegate.h"
-#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_favicon_mediator.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator_util.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_metrics_recorder.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_tile_saver.h"
@@ -110,6 +109,7 @@
 #import "ios/chrome/browser/ui/content_suggestions/tab_resumption/tab_resumption_helper.h"
 #import "ios/chrome/browser/ui/content_suggestions/tab_resumption/tab_resumption_item.h"
 #import "ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_metrics.h"
+#import "ios/chrome/browser/ui/favicon/favicon_attributes_provider.h"
 #import "ios/chrome/browser/ui/ntp/metrics/home_metrics.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_feature.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_metrics_delegate.h"
@@ -134,6 +134,12 @@
 // Maximum number of most visited tiles fetched.
 const NSInteger kMaxNumMostVisitedTiles = 4;
 
+// Size of the favicon returned by the provider for the most visited items.
+const CGFloat kMostVisitedFaviconSize = 48;
+// Size below which the provider returns a colored tile instead of an image.
+const CGFloat kMostVisitedFaviconMinimalSize = 32;
+const CGFloat kMagicStackMostVisitedFaviconMinimalSize = 18;
+
 // Checks the last action the user took on the Credential Provider Promo to
 // determine if it was dismissed.
 bool CredentialProviderPromoDismissed(PrefService* local_state) {
@@ -200,8 +206,6 @@
     ContentSuggestionsSectionInformation* mostVisitedSectionInfo;
 // Whether the page impression has been recorded.
 @property(nonatomic, assign) BOOL recordedPageImpression;
-// Mediator fetching the favicons for the items.
-@property(nonatomic, strong) ContentSuggestionsFaviconMediator* faviconMediator;
 // Item for the reading list action item.  Reference is used to update the
 // reading list count.
 @property(nonatomic, strong)
@@ -265,6 +269,8 @@
   NSArray<NSNumber*>* _latestMagicStackOrder;
   commerce::ShoppingService* _shoppingService;
   NSArray<ParcelTrackingItem*>* _parcelTrackingItems;
+  FaviconAttributesProvider* _mostVisitedAttributesProvider;
+  std::map<GURL, FaviconCompletionHandler> _mostVisitedFetchFaviconCallbacks;
 }
 
 #pragma mark - Public
@@ -291,9 +297,17 @@
     _contentSuggestionsPolicyEnabled =
         prefService->FindPreference(prefs::kNTPContentSuggestionsEnabled);
 
-    _faviconMediator = [[ContentSuggestionsFaviconMediator alloc]
-        initWithLargeIconService:largeIconService
-                  largeIconCache:largeIconCache];
+    _mostVisitedAttributesProvider = [[FaviconAttributesProvider alloc]
+        initWithFaviconSize:IsMagicStackEnabled() ? kMagicStackFaviconWidth
+                                                  : kMostVisitedFaviconSize
+             minFaviconSize:IsMagicStackEnabled()
+                                ? kMagicStackMostVisitedFaviconMinimalSize
+                                : kMostVisitedFaviconMinimalSize
+           largeIconService:largeIconService];
+    // Set a cache only for the Most Visited provider, as the cache is
+    // overwritten for every new results and the size of the favicon fetched for
+    // the suggestions is much smaller.
+    _mostVisitedAttributesProvider.cache = largeIconCache;
 
     _logoSectionInfo = LogoSectionInformation();
     _mostVisitedSectionInfo = MostVisitedSectionInformation();
@@ -448,7 +462,6 @@
 
 - (void)setConsumer:(id<ContentSuggestionsConsumer>)consumer {
   _consumer = consumer;
-  self.faviconMediator.consumer = consumer;
   [self configureConsumer];
 }
 
@@ -790,6 +803,15 @@
   [self showMostVisitedUndoForURL:item.URL];
 }
 
+#pragma mark - ContentSuggestionsImageDataSource
+
+- (void)fetchFaviconForURL:(const GURL&)URL
+                completion:(FaviconCompletionHandler)completion {
+  _mostVisitedFetchFaviconCallbacks[URL] = completion;
+  [_mostVisitedAttributesProvider fetchFaviconAttributesForURL:URL
+                                                    completion:completion];
+}
+
 #pragma mark - StartSurfaceRecentTabObserving
 
 - (void)mostRecentTabWasRemoved:(web::WebState*)webState {
@@ -831,7 +853,7 @@
     (const ntp_tiles::NTPTilesVector&)mostVisited {
   // This is used by the content widget.
   content_suggestions_tile_saver::SaveMostVisitedToDisk(
-      mostVisited, self.faviconMediator.mostVisitedAttributesProvider,
+      mostVisited, _mostVisitedAttributesProvider,
       app_group::ContentWidgetFaviconsFolder());
 
   self.freshMostVisitedItems = [NSMutableArray array];
@@ -844,7 +866,6 @@
     item.index = index;
     DCHECK(index < kShortcutMinimumIndex);
     index++;
-    [self.faviconMediator fetchFaviconForMostVisited:item];
     [self.freshMostVisitedItems addObject:item];
   }
 
@@ -853,7 +874,6 @@
   if (mostVisited.size() && !self.recordedPageImpression) {
     self.recordedPageImpression = YES;
     [self recordMostVisitedTilesDisplayed];
-    [self.faviconMediator setMostVisitedDataForLogging:mostVisited];
     ntp_tiles::metrics::RecordPageImpression(mostVisited.size());
   }
 }
@@ -861,12 +881,18 @@
 - (void)onIconMadeAvailable:(const GURL&)siteURL {
   // This is used by the content widget.
   content_suggestions_tile_saver::UpdateSingleFavicon(
-      siteURL, self.faviconMediator.mostVisitedAttributesProvider,
+      siteURL, _mostVisitedAttributesProvider,
       app_group::ContentWidgetFaviconsFolder());
 
   for (ContentSuggestionsMostVisitedItem* item in self.mostVisitedItems) {
     if (item.URL == siteURL) {
-      [self.faviconMediator fetchFaviconForMostVisited:item];
+      FaviconCompletionHandler completion =
+          _mostVisitedFetchFaviconCallbacks[siteURL];
+      if (completion) {
+        [_mostVisitedAttributesProvider
+            fetchFaviconAttributesForURL:siteURL
+                              completion:completion];
+      }
       return;
     }
   }
@@ -1754,10 +1780,7 @@
 
 - (void)setContentSuggestionsMetricsRecorder:
     (ContentSuggestionsMetricsRecorder*)contentSuggestionsMetricsRecorder {
-  CHECK(self.faviconMediator);
   _contentSuggestionsMetricsRecorder = contentSuggestionsMetricsRecorder;
-  self.faviconMediator.contentSuggestionsMetricsRecorder =
-      self.contentSuggestionsMetricsRecorder;
 }
 
 - (BOOL)contentSuggestionsEnabled {
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.h
index 0663506..f0c9757a 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.h
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.h
@@ -10,6 +10,7 @@
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_consumer.h"
 
 @protocol ContentSuggestionsCommands;
+@protocol ContentSuggestionsImageDataSource;
 @protocol ContentSuggestionsMenuProvider;
 @protocol ContentSuggestionsViewControllerAudience;
 @protocol ParcelTrackingOptInCommands;
@@ -33,6 +34,9 @@
 // Handler for the commands sent by the ContentSuggestionsViewController.
 @property(nonatomic, weak) id<ContentSuggestionsCommands>
     suggestionCommandHandler;
+// Datasource to fetch favicons.
+@property(nonatomic, weak) id<ContentSuggestionsImageDataSource>
+    imageDataSource;
 @property(nonatomic, weak) id<ContentSuggestionsViewControllerAudience,
                               SafetyCheckViewDelegate,
                               SetUpListViewDelegate>
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
index 0abfc89..022742c 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
@@ -40,6 +40,7 @@
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_commands.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.h"
+#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_image_data_source.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_menu_provider.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_metrics_recorder.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller_audience.h"
@@ -424,6 +425,22 @@
         stringWithFormat:
             @"%@%li",
             kContentSuggestionsMostVisitedAccessibilityIdentifierPrefix, index];
+
+    __weak ContentSuggestionsMostVisitedItem* weakItem = item;
+    __weak ContentSuggestionsMostVisitedTileView* weakView = view;
+    void (^completion)(FaviconAttributes*) = ^(FaviconAttributes* attributes) {
+      ContentSuggestionsMostVisitedTileView* strongView = weakView;
+      ContentSuggestionsMostVisitedItem* strongItem = weakItem;
+      if (!strongView || !weakItem) {
+        return;
+      }
+
+      strongItem.attributes = attributes;
+      [strongView.faviconView configureWithAttributes:attributes];
+    };
+    [self.imageDataSource fetchFaviconForURL:item.URL completion:completion];
+    [self.contentSuggestionsMetricsRecorder recordMostVisitedTileShown:item
+                                                               atIndex:index];
     [self.mostVisitedViews addObject:view];
     index++;
   }
@@ -489,17 +506,6 @@
   }
 }
 
-- (void)updateMostVisitedTileConfig:(ContentSuggestionsMostVisitedItem*)config {
-  for (ContentSuggestionsMostVisitedTileView* view in self.mostVisitedViews) {
-    if (view.config == config) {
-      dispatch_async(dispatch_get_main_queue(), ^{
-        [view.faviconView configureWithAttributes:config.attributes];
-      });
-      return;
-    }
-  }
-}
-
 - (void)setMagicStackOrder:(NSArray<NSNumber*>*)order {
   CHECK([order count] > 0);
   _magicStackRankReceived = YES;
diff --git a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_action_list.swift b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_action_list.swift
index 301743f..75a18dcd 100644
--- a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_action_list.swift
+++ b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_action_list.swift
@@ -18,9 +18,18 @@
 
   var body: some View {
     List {
-      ForEach(actionGroups.filter({ !$0.actions.isEmpty })) { actionGroup in
+      let nonEmpty = actionGroups.filter({ !$0.actions.isEmpty })
+      ForEach(nonEmpty) { actionGroup in
+        let isLast = actionGroup == nonEmpty.last
         OverflowMenuActionSection(
-          actionGroup: actionGroup, metricsHandler: metricsHandler)
+          actionGroup: actionGroup, metricsHandler: metricsHandler,
+          footerBackground: {
+            if isLast {
+              Color.clear.onAppear {
+                metricsHandler?.popupMenuUserScrolledToEndOfActions()
+              }
+            }
+          })
       }
     }
     .matchedGeometryEffect(id: MenuCustomizationAnimationID.actions, in: namespace)
diff --git a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_action_section.swift b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_action_section.swift
index fd410b3..306a3c3 100644
--- a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_action_section.swift
+++ b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_action_section.swift
@@ -6,18 +6,28 @@
 
 /// A SwiftUI view for the overflow menu displaying a subsection of the actions list.
 @available(iOS 15, *)
-struct OverflowMenuActionSection: View {
+struct OverflowMenuActionSection<FooterBackground: View>: View {
 
-  enum Dimensions {
-    // Default height if no other header or footer. This spaces the sections
-    // out properly.
-    static let headerFooterHeight: CGFloat = 20
-  }
+  // Default height if no other header or footer. This spaces the sections
+  // out properly.
+  static var headerFooterHeight: CGFloat { 20 }
 
   @ObservedObject var actionGroup: OverflowMenuActionGroup
 
   weak var metricsHandler: PopupMenuMetricsHandler?
 
+  // A custom background for the footer if provided.
+  let footerBackground: FooterBackground
+
+  init(
+    actionGroup: OverflowMenuActionGroup, metricsHandler: PopupMenuMetricsHandler? = nil,
+    @ViewBuilder footerBackground: () -> FooterBackground = { EmptyView() }
+  ) {
+    self.actionGroup = actionGroup
+    self.metricsHandler = metricsHandler
+    self.footerBackground = footerBackground()
+  }
+
   var body: some View {
     Section(
       content: {
@@ -29,13 +39,16 @@
       },
       header: {
         Spacer()
-          .frame(height: Dimensions.headerFooterHeight)
+          .frame(height: Self.headerFooterHeight)
           .listRowInsets(EdgeInsets())
           .accessibilityHidden(true)
       },
       footer: {
         if let actionFooter = actionGroup.footer {
           OverflowMenuFooterRow(footer: actionFooter)
+            .background {
+              footerBackground
+            }
         } else {
           Spacer()
             // Use `leastNonzeroMagnitude` to remove the footer. Otherwise,
@@ -43,6 +56,9 @@
             .frame(height: CGFloat.leastNonzeroMagnitude)
             .listRowInsets(EdgeInsets())
             .accessibilityHidden(true)
+            .background {
+              footerBackground
+            }
         }
       })
   }
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_coordinator.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_coordinator.mm
index 195b6f2..a17f6a6 100644
--- a/ios/chrome/browser/ui/popup_menu/popup_menu_coordinator.mm
+++ b/ios/chrome/browser/ui/popup_menu/popup_menu_coordinator.mm
@@ -119,6 +119,9 @@
 // Whether the user selected a Destination on the overflow menu (the horizontal
 // list).
 @property(nonatomic, assign) BOOL overflowMenuUserSelectedDestination;
+// Whether the user scrolled to the end of the actions section during their
+// interaction.
+@property(nonatomic, assign) BOOL overflowMenuUserScrolledToEndOfActions;
 
 @property(nonatomic, strong) PopupMenuHelpCoordinator* popupMenuHelpCoordinator;
 
@@ -519,6 +522,14 @@
 
     RecordOverflowMenuVisitedEvent(_event);
 
+    if (IsOverflowMenuCustomizationEnabled() &&
+        self.overflowMenuUserScrolledToEndOfActions) {
+      base::UmaHistogramBoolean(
+          "IOS.OverflowMenu.UserScrolledToEndAndStartedCustomization",
+          _event.Has(
+              OverflowMenuVisitedEventFields::kUserStartedCustomization));
+    }
+
     _event = OverflowMenuVisitedEvent();
 
     self.toolsMenuWasScrolledVertically = NO;
@@ -526,6 +537,7 @@
     self.toolsMenuUserTookAction = NO;
     self.overflowMenuUserSelectedAction = NO;
     self.overflowMenuUserSelectedDestination = NO;
+    self.overflowMenuUserScrolledToEndOfActions = NO;
   }
 
   if (self.overflowMenuMediator) {
@@ -689,6 +701,10 @@
   _event.Put(OverflowMenuVisitedEventFields::kUserSelectedDestination);
 }
 
+- (void)popupMenuUserScrolledToEndOfActions {
+  self.overflowMenuUserScrolledToEndOfActions = YES;
+}
+
 #pragma mark - Notification callback
 
 - (void)applicationDidEnterBackground:(NSNotification*)note {
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_metrics_handler.h b/ios/chrome/browser/ui/popup_menu/popup_menu_metrics_handler.h
index 8694736..406683a 100644
--- a/ios/chrome/browser/ui/popup_menu/popup_menu_metrics_handler.h
+++ b/ios/chrome/browser/ui/popup_menu/popup_menu_metrics_handler.h
@@ -26,6 +26,9 @@
 // list).
 - (void)popupMenuUserSelectedDestination;
 
+// Called when the user scrolls to the end of the action list.
+- (void)popupMenuUserScrolledToEndOfActions;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_POPUP_MENU_POPUP_MENU_METRICS_HANDLER_H_
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_settings_profile_edit_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/autofill/autofill_settings_profile_edit_table_view_controller_unittest.mm
index aaebad5..58e454a 100644
--- a/ios/chrome/browser/ui/settings/autofill/autofill_settings_profile_edit_table_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/settings/autofill/autofill_settings_profile_edit_table_view_controller_unittest.mm
@@ -163,10 +163,9 @@
 
     autofill::AutofillProfile profile = autofill::test::GetFullProfile2();
     NSString* countryCode = base::SysUTF16ToNSString(
-        profile.GetRawInfo(autofill::ServerFieldType::ADDRESS_HOME_COUNTRY));
+        profile.GetRawInfo(autofill::FieldType::ADDRESS_HOME_COUNTRY));
 
-    std::vector<std::pair<autofill::ServerFieldType, std::u16string>>
-        expected_values;
+    std::vector<std::pair<autofill::FieldType, std::u16string>> expected_values;
     for (size_t i = 0; i < std::size(kProfileFieldsToDisplay); ++i) {
       const AutofillProfileFieldDisplayInfo& field = kProfileFieldsToDisplay[i];
       if (!FieldIsUsedInAddress(field.autofillType, countryCode)) {
diff --git a/ios/chrome/browser/ui/settings/password/password_details/BUILD.gn b/ios/chrome/browser/ui/settings/password/password_details/BUILD.gn
index a08de157..2e0a997 100644
--- a/ios/chrome/browser/ui/settings/password/password_details/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/password/password_details/BUILD.gn
@@ -105,6 +105,7 @@
     "//ios/chrome/browser/ui/settings:settings_root",
     "//ios/chrome/browser/ui/settings/autofill",
     "//ios/chrome/browser/ui/settings/cells",
+    "//ios/chrome/browser/ui/settings/elements:enterprise_info_popover_view_controller",
     "//ios/chrome/browser/ui/settings/password:features",
     "//ios/chrome/browser/ui/settings/password:password_constants",
     "//ios/chrome/browser/ui/settings/password/password_details/cells",
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_consumer.h b/ios/chrome/browser/ui/settings/password/password_details/password_details_consumer.h
index 51db16a6..4fddc37 100644
--- a/ios/chrome/browser/ui/settings/password/password_details/password_details_consumer.h
+++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_consumer.h
@@ -24,8 +24,10 @@
 // Set the signed in user email.
 - (void)setUserEmail:(NSString*)userEmail;
 
-// Sets up the share button next to the navigation's right bar button.
-- (void)setupRightShareButton;
+// Sets up the share button next to the navigation's right bar button. Tapping
+// on the button results in entering the sharing flow when `enabled`. Otherwise,
+// info popup is displayed explaining that the feature is disabled by policy.
+- (void)setupRightShareButton:(BOOL)enabled;
 
 @end
 
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.mm b/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.mm
index d7cdcbc..d37ea12436 100644
--- a/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.mm
+++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.mm
@@ -201,8 +201,10 @@
     [_consumer setIsBlockedSite:YES];
   }
 
-  if ([self isUserEligibleForSendingPasswords]) {
-    [_consumer setupRightShareButton];
+  if ([self shouldDisplayShareButton]) {
+    [_consumer setupRightShareButton:
+                   _prefService->GetBoolean(
+                       password_manager::prefs::kPasswordSharingEnabled)];
   }
 }
 
@@ -556,11 +558,8 @@
 // Returns YES if all of the following conditions are met:
 // * User is syncing or signed in and opted in to account storage.
 // * Password sending feature is enabled.
-// * Password sharing pref is enabled.
-- (BOOL)isUserEligibleForSendingPasswords {
+- (BOOL)shouldDisplayShareButton {
   return password_manager::sync_util::GetAccountForSaving(_syncService) &&
-         _prefService->GetBoolean(
-             password_manager::prefs::kPasswordSharingEnabled) &&
          base::FeatureList::IsEnabled(
              password_manager::features::kSendPasswords);
 }
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator_unittest.mm b/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator_unittest.mm
index 15ccb65..349e1677 100644
--- a/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator_unittest.mm
@@ -88,7 +88,7 @@
 - (void)setUserEmail:(NSString*)userEmail {
 }
 
-- (void)setupRightShareButton {
+- (void)setupRightShareButton:(BOOL)enabled {
 }
 
 @end
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm b/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm
index 8714ab7c..d944dec 100644
--- a/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm
@@ -31,6 +31,7 @@
 #import "ios/chrome/browser/shared/ui/util/pasteboard_util.h"
 #import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.h"
+#import "ios/chrome/browser/ui/settings/elements/enterprise_info_popover_view_controller.h"
 #import "ios/chrome/browser/ui/settings/password/password_details/cells/table_view_stacked_details_item.h"
 #import "ios/chrome/browser/ui/settings/password/password_details/password_details.h"
 #import "ios/chrome/browser/ui/settings/password/password_details/password_details_consumer.h"
@@ -830,13 +831,15 @@
   _userEmail = userEmail;
 }
 
-- (void)setupRightShareButton {
+- (void)setupRightShareButton:(BOOL)enabled {
+  SEL selector = enabled ? @selector(onShareButtonPressed)
+                         : @selector(onPolicyDisabledShareButtonPressed:);
   UIBarButtonItem* shareButton = [[UIBarButtonItem alloc]
       initWithImage:DefaultSymbolWithPointSize(kShareSymbol,
                                                kSymbolActionPointSize)
               style:UIBarButtonItemStylePlain
              target:self
-             action:@selector(onShareButtonPressed)];
+             action:selector];
   shareButton.accessibilityIdentifier = kPasswordShareButtonID;
   self.navigationItem.rightBarButtonItems =
       @[ self.navigationItem.rightBarButtonItem, shareButton ];
@@ -1266,11 +1269,32 @@
                              repeats:NO];
 }
 
+// Notifies the handler that the share button was pressed by the user.
 - (void)onShareButtonPressed {
   CHECK(self.handler);
   [self.handler onShareButtonPressed];
 }
 
+// Displays the popup informing that password sharing is disabled by the
+// administrator.
+- (void)onPolicyDisabledShareButtonPressed:(UIBarButtonItem*)button {
+  EnterpriseInfoPopoverViewController* popoverViewController =
+      [[EnterpriseInfoPopoverViewController alloc]
+                 initWithMessage:
+                     l10n_util::GetNSString(
+                         IDS_IOS_PASSWORD_SHARING_ENTERPRISE_POLICY_DISABLED_MESSAGE)
+                  enterpriseName:nil
+          isPresentingFromButton:YES
+                addLearnMoreLink:NO];
+  popoverViewController.popoverPresentationController.barButtonItem = button;
+  popoverViewController.popoverPresentationController.permittedArrowDirections =
+      UIPopoverArrowDirectionAny;
+
+  [self presentViewController:popoverViewController
+                     animated:YES
+                   completion:nil];
+}
+
 #pragma mark - AutofillEditTableViewController
 
 - (BOOL)isItemAtIndexPathTextEditCell:(NSIndexPath*)cellPath {
diff --git a/ios/chrome/browser/ui/settings/password/password_sharing/BUILD.gn b/ios/chrome/browser/ui/settings/password/password_sharing/BUILD.gn
index ae0e322..251417eb 100644
--- a/ios/chrome/browser/ui/settings/password/password_sharing/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/password/password_sharing/BUILD.gn
@@ -161,6 +161,7 @@
     "//ios/chrome/browser/shared/model/prefs:pref_names",
     "//ios/chrome/browser/signin/model:fake_system_identity",
     "//ios/chrome/browser/ui/authentication:eg_test_support+eg2",
+    "//ios/chrome/browser/ui/settings/elements:constants",
     "//ios/chrome/browser/ui/settings/password:eg_test_support",
     "//ios/chrome/browser/ui/settings/password:eg_test_support+eg2",
     "//ios/chrome/browser/ui/settings/password:features",
diff --git a/ios/chrome/browser/ui/settings/password/password_sharing/password_sharing_egtest.mm b/ios/chrome/browser/ui/settings/password/password_sharing/password_sharing_egtest.mm
index 43da10f..4edf1ac6 100644
--- a/ios/chrome/browser/ui/settings/password/password_sharing/password_sharing_egtest.mm
+++ b/ios/chrome/browser/ui/settings/password/password_sharing/password_sharing_egtest.mm
@@ -9,6 +9,7 @@
 #import "ios/chrome/browser/shared/model/prefs/pref_names.h"
 #import "ios/chrome/browser/signin/model/fake_system_identity.h"
 #import "ios/chrome/browser/ui/authentication/signin_earl_grey_ui_test_util.h"
+#import "ios/chrome/browser/ui/settings/elements/elements_constants.h"
 #import "ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_constants.h"
 #import "ios/chrome/browser/ui/settings/password/password_manager_egtest_utils.h"
 #import "ios/chrome/browser/ui/settings/password/password_manager_ui_features.h"
@@ -204,9 +205,17 @@
   SignInAndEnableSync();
   [self saveExamplePasswordAndOpenDetails];
 
+  // Share button should be visible and display the policy info popup upon tap.
   [[EarlGrey
       selectElementWithMatcher:grey_accessibilityID(kPasswordShareButtonID)]
-      assertWithMatcher:grey_not(grey_sufficientlyVisible())];
+      assertWithMatcher:grey_sufficientlyVisible()];
+  [[EarlGrey
+      selectElementWithMatcher:grey_accessibilityID(kPasswordShareButtonID)]
+      performAction:grey_tap()];
+
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          kEnterpriseInfoBubbleViewId)]
+      assertWithMatcher:grey_sufficientlyVisible()];
 }
 
 - (void)testFamilyPickerCancelFlow {
diff --git a/ios/chrome/browser/web/chrome_web_client.h b/ios/chrome/browser/web/chrome_web_client.h
index 10835cd..132de2e 100644
--- a/ios/chrome/browser/web/chrome_web_client.h
+++ b/ios/chrome/browser/web/chrome_web_client.h
@@ -66,6 +66,8 @@
   bool IsBrowserLockdownModeEnabled(web::BrowserState* browser_state) override;
   void SetOSLockdownModeEnabled(web::BrowserState* browser_state,
                                 bool enabled) override;
+  bool IsInsecureFormWarningEnabled(
+      web::BrowserState* browser_state) const override;
 
  private:
   // Reference to a view that is attached to a window.
diff --git a/ios/chrome/browser/web/chrome_web_client.mm b/ios/chrome/browser/web/chrome_web_client.mm
index f973421..6d2f674 100644
--- a/ios/chrome/browser/web/chrome_web_client.mm
+++ b/ios/chrome/browser/web/chrome_web_client.mm
@@ -565,3 +565,17 @@
   PrefService* prefs = chrome_browser_state->GetPrefs();
   prefs->SetBoolean(prefs::kOSLockdownModeEnabled, enabled);
 }
+
+bool ChromeWebClient::IsInsecureFormWarningEnabled(
+    web::BrowserState* browser_state) const {
+  ChromeBrowserState* chrome_browser_state =
+      ChromeBrowserState::FromBrowserState(browser_state);
+  if (!chrome_browser_state->GetPrefs()->GetBoolean(
+          prefs::kInsecureFormWarningsEnabled) &&
+      chrome_browser_state->GetPrefs()->IsManagedPreference(
+          prefs::kInsecureFormWarningsEnabled)) {
+    return false;
+  }
+  return base::FeatureList::IsEnabled(
+      security_interstitials::features::kInsecureFormSubmissionInterstitial);
+}
diff --git a/ios/chrome/test/app/sync_test_util.h b/ios/chrome/test/app/sync_test_util.h
index 7989114..fdea6a4 100644
--- a/ios/chrome/test/app/sync_test_util.h
+++ b/ios/chrome/test/app/sync_test_util.h
@@ -38,6 +38,11 @@
 // nothing.
 void ClearFakeSyncServerData();
 
+// Ensures that all of the FakeServer's data is persisted to disk. This is
+// useful before app restarts, where otherwise the FakeServer may not get to do
+// its usual on-destruction flush.
+void FlushFakeSyncServerToDisk();
+
 // Triggers a sync cycle for a `type`.
 void TriggerSyncCycle(syncer::ModelType type);
 
diff --git a/ios/chrome/test/app/sync_test_util.mm b/ios/chrome/test/app/sync_test_util.mm
index 668d2e5..ba55dab 100644
--- a/ios/chrome/test/app/sync_test_util.mm
+++ b/ios/chrome/test/app/sync_test_util.mm
@@ -114,6 +114,11 @@
   }
 }
 
+void FlushFakeSyncServerToDisk() {
+  DCHECK(gSyncFakeServer);
+  gSyncFakeServer->FlushToDisk();
+}
+
 void TriggerSyncCycle(syncer::ModelType type) {
   ChromeBrowserState* browser_state =
       chrome_test_util::GetOriginalBrowserState();
diff --git a/ios/chrome/test/data/policy/policy_test_bundle_data.filelist b/ios/chrome/test/data/policy/policy_test_bundle_data.filelist
index 95919ca8..90a587c 100644
--- a/ios/chrome/test/data/policy/policy_test_bundle_data.filelist
+++ b/ios/chrome/test/data/policy/policy_test_bundle_data.filelist
@@ -39,6 +39,7 @@
 //ios/chrome/test/data/policy/pref_mapping/IdleTimeout.json
 //ios/chrome/test/data/policy/pref_mapping/IdleTimeoutActions.json
 //ios/chrome/test/data/policy/pref_mapping/IncognitoModeAvailability.json
+//ios/chrome/test/data/policy/pref_mapping/InsecureFormsWarningsEnabled.json
 //ios/chrome/test/data/policy/pref_mapping/LensCameraAssistedSearchEnabled.json
 //ios/chrome/test/data/policy/pref_mapping/ManagedBookmarks.json
 //ios/chrome/test/data/policy/pref_mapping/MetricsReportingEnabled.json
diff --git a/ios/chrome/test/data/policy/pref_mapping/InsecureFormsWarningsEnabled.json b/ios/chrome/test/data/policy/pref_mapping/InsecureFormsWarningsEnabled.json
new file mode 100644
index 0000000..22eaf8e
--- /dev/null
+++ b/ios/chrome/test/data/policy/pref_mapping/InsecureFormsWarningsEnabled.json
@@ -0,0 +1,27 @@
+[
+  {
+    "os": [
+      "ios"
+    ],
+    "policy_pref_mapping_tests": [
+      {
+        "note": "Default value (no policies set).",
+        "prefs": {
+          "ios.insecure_form_warnings_enabled": {
+            "default_value": true
+          }
+        }
+      },
+      {
+        "policies": {
+          "InsecureFormsWarningsEnabled": false
+        },
+        "prefs": {
+          "ios.insecure_form_warnings_enabled": {
+            "value": false
+          }
+        }
+      }
+    ]
+  }
+]
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey.h b/ios/chrome/test/earl_grey/chrome_earl_grey.h
index 2c7c2e80..251567d 100644
--- a/ios/chrome/test/earl_grey/chrome_earl_grey.h
+++ b/ios/chrome/test/earl_grey/chrome_earl_grey.h
@@ -227,6 +227,11 @@
 // Clears fake sync server data if the server is running.
 - (void)clearFakeSyncServerData;
 
+// Ensures that all of the FakeServer's data is persisted to disk. This is
+// useful before app restarts, where otherwise the FakeServer may not get to do
+// its usual on-destruction flush.
+- (void)flushFakeSyncServerToDisk;
+
 // Gets the number of entities of the given `type`.
 - (int)numberOfSyncEntitiesWithType:(syncer::ModelType)type [[nodiscard]];
 
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey.mm b/ios/chrome/test/earl_grey/chrome_earl_grey.mm
index c6d40cb..6e6cd27 100644
--- a/ios/chrome/test/earl_grey/chrome_earl_grey.mm
+++ b/ios/chrome/test/earl_grey/chrome_earl_grey.mm
@@ -850,6 +850,10 @@
   [ChromeEarlGreyAppInterface clearFakeSyncServerData];
 }
 
+- (void)flushFakeSyncServerToDisk {
+  [ChromeEarlGreyAppInterface flushFakeSyncServerToDisk];
+}
+
 - (int)numberOfSyncEntitiesWithType:(syncer::ModelType)type {
   return [ChromeEarlGreyAppInterface numberOfSyncEntitiesWithType:type];
 }
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.h b/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.h
index 8d11a6a..be61498 100644
--- a/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.h
+++ b/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.h
@@ -383,6 +383,11 @@
 // Clears fake sync server data if the server is running.
 + (void)clearFakeSyncServerData;
 
+// Ensures that all of the FakeServer's data is persisted to disk. This is
+// useful before app restarts, where otherwise the FakeServer may not get to do
+// its usual on-destruction flush.
++ (void)flushFakeSyncServerToDisk;
+
 // Gets the number of entities of the given `type`.
 + (int)numberOfSyncEntitiesWithType:(syncer::ModelType)type;
 
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.mm b/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.mm
index cb642f8..402bc12 100644
--- a/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.mm
+++ b/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.mm
@@ -1013,6 +1013,10 @@
   chrome_test_util::ClearFakeSyncServerData();
 }
 
++ (void)flushFakeSyncServerToDisk {
+  chrome_test_util::FlushFakeSyncServerToDisk();
+}
+
 + (NSError*)verifyNumberOfSyncEntitiesWithType:(NSUInteger)type
                                           name:(NSString*)name
                                          count:(NSUInteger)count {
diff --git a/ios/components/cookie_util/cookie_util.h b/ios/components/cookie_util/cookie_util.h
index 20b4544b..6b503737 100644
--- a/ios/components/cookie_util/cookie_util.h
+++ b/ios/components/cookie_util/cookie_util.h
@@ -11,7 +11,6 @@
 #include "net/cookies/canonical_cookie.h"
 
 namespace net {
-class CookieCryptoDelegate;
 class CookieStore;
 class SystemCookieStore;
 class NetLog;
@@ -53,22 +52,14 @@
   // If `path` is empty, then this specifies an in-memory cookie store.
   // With in-memory cookie stores, `session_cookie_mode` must be
   // EPHEMERAL_SESSION_COOKIES.
-  // Note: If `crypto_delegate` is non-null, it must outlive any CookieStores
-  // created using this config.
   CookieStoreConfig(const base::FilePath& path,
                     SessionCookieMode session_cookie_mode,
-                    CookieStoreType cookie_store_type,
-                    net::CookieCryptoDelegate* crypto_delegate);
+                    CookieStoreType cookie_store_type);
   ~CookieStoreConfig();
 
   const base::FilePath path;
   const SessionCookieMode session_cookie_mode;
   const CookieStoreType cookie_store_type;
-
-  // Used to provide encryption hooks for the cookie store. The
-  // CookieCryptoDelegate must outlive any cookie store created with this
-  // config.
-  net::CookieCryptoDelegate* crypto_delegate;
 };
 
 // Creates a cookie store which is internally either a CookieMonster or a
diff --git a/ios/components/cookie_util/cookie_util.mm b/ios/components/cookie_util/cookie_util.mm
index b19e24d8..598b625d 100644
--- a/ios/components/cookie_util/cookie_util.mm
+++ b/ios/components/cookie_util/cookie_util.mm
@@ -37,15 +37,14 @@
 // Creates a SQLitePersistentCookieStore running on a background thread.
 scoped_refptr<net::SQLitePersistentCookieStore> CreatePersistentCookieStore(
     const base::FilePath& path,
-    bool restore_old_session_cookies,
-    net::CookieCryptoDelegate* crypto_delegate) {
+    bool restore_old_session_cookies) {
   return scoped_refptr<net::SQLitePersistentCookieStore>(
       new net::SQLitePersistentCookieStore(
           path, web::GetIOThreadTaskRunner({}),
           base::ThreadPool::CreateSequencedTaskRunner(
               {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
                base::TaskShutdownBehavior::BLOCK_SHUTDOWN}),
-          restore_old_session_cookies, crypto_delegate,
+          restore_old_session_cookies, /*crypto_delegate=*/nullptr,
           /*enable_exclusive_access=*/false));
 }
 
@@ -61,8 +60,7 @@
   const bool restore_old_session_cookies =
       config.session_cookie_mode == CookieStoreConfig::RESTORED_SESSION_COOKIES;
   scoped_refptr<net::SQLitePersistentCookieStore> persistent_store =
-      CreatePersistentCookieStore(config.path, restore_old_session_cookies,
-                                  config.crypto_delegate);
+      CreatePersistentCookieStore(config.path, restore_old_session_cookies);
   std::unique_ptr<net::CookieMonster> cookie_monster(
       new net::CookieMonster(persistent_store.get(), net_log));
   if (restore_old_session_cookies)
@@ -74,12 +72,10 @@
 
 CookieStoreConfig::CookieStoreConfig(const base::FilePath& path,
                                      SessionCookieMode session_cookie_mode,
-                                     CookieStoreType cookie_store_type,
-                                     net::CookieCryptoDelegate* crypto_delegate)
+                                     CookieStoreType cookie_store_type)
     : path(path),
       session_cookie_mode(session_cookie_mode),
-      cookie_store_type(cookie_store_type),
-      crypto_delegate(crypto_delegate) {
+      cookie_store_type(cookie_store_type) {
   CHECK(!path.empty() || session_cookie_mode == EPHEMERAL_SESSION_COOKIES);
 }
 
diff --git a/ios/components/cookie_util/cookie_util_unittest.mm b/ios/components/cookie_util/cookie_util_unittest.mm
index 3efd1baf..0af89fc8 100644
--- a/ios/components/cookie_util/cookie_util_unittest.mm
+++ b/ios/components/cookie_util/cookie_util_unittest.mm
@@ -79,8 +79,7 @@
   cookie_util::CookieStoreConfig config(
       base::FilePath(),
       cookie_util::CookieStoreConfig::EPHEMERAL_SESSION_COOKIES,
-      cookie_util::CookieStoreConfig::CookieStoreType::COOKIE_STORE_IOS,
-      nullptr);
+      cookie_util::CookieStoreConfig::CookieStoreType::COOKIE_STORE_IOS);
   std::unique_ptr<net::CookieStore> cookie_store =
       cookie_util::CreateCookieStore(config, std::move(system_cookie_store),
                                      nullptr /* net_log */);
diff --git a/ios/components/security_interstitials/safe_browsing/safe_browsing_service_impl.mm b/ios/components/security_interstitials/safe_browsing/safe_browsing_service_impl.mm
index a0c453dd..1eba4e2e 100644
--- a/ios/components/security_interstitials/safe_browsing/safe_browsing_service_impl.mm
+++ b/ios/components/security_interstitials/safe_browsing/safe_browsing_service_impl.mm
@@ -324,8 +324,7 @@
           cookie_util::CookieStoreConfig(
               cookie_file_path,
               cookie_util::CookieStoreConfig::RESTORED_SESSION_COOKIES,
-              cookie_util::CookieStoreConfig::COOKIE_MONSTER,
-              /*crypto_delegate=*/nullptr),
+              cookie_util::CookieStoreConfig::COOKIE_MONSTER),
           /*system_cookie_store=*/nullptr, net::NetLog::Get());
 
   builder.SetCookieStore(std::move(cookie_store));
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
index 24071df..17b7c46 100644
--- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-8557f6c59a039ebfbe6ed769dbdec3c997174457
\ No newline at end of file
+8f09bc0338149bf7bcd453eaca2860a499caceb2
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
index e81f3952..3fc94cd 100644
--- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-85e21736748fb0986e37b0c6b246a2593965a973
\ No newline at end of file
+ebd796bc9ed764965851a9d20b457ab5cf9aa0d7
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
index e49fa33..7663298 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-3c6a15158ed534fd54772773f24c0035a8fc68ac
\ No newline at end of file
+63934a8948dd25d6bc7cd322ebb5c3c3486b8e7b
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
index 4724a66..65d9e02 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-9d5f7eb678f15498bda7ebe42a623df5c31b70fc
\ No newline at end of file
+a79e0099814a8210339c05243acac64083c272f9
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
index f8dfb3b..9f09e36f 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-4baec1cbe31bcfef50816515ee99fb7d467aa230
\ No newline at end of file
+aa69ff592ef9491f567df0ae63fc8c3b22514dbd
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
index 95af6165..48d30d54 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-97958ac6708fb20c201253eee734aa5e13c11880
\ No newline at end of file
+fb7f3e174ae6413604583590b4ce7e0e8c2521d2
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
index 7ce7ba81..b6e67263 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-565fb925c2b2385edaa7b4e10021d0a9f433a1d8
\ No newline at end of file
+7b013a3dd237a1084b3ffd766f60ff4b3064c0e5
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
index d21cf10..1855f15 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-9b3fcd8c92bc0bf9f2847ddc818c362a85a52b8d
\ No newline at end of file
+23ee053f781d7cadfad55adb884f4867be4b2646
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
index d627c21..4829b05 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-660e2dca2caafbdadb9f08ecf346ed7e74ec7e7d
\ No newline at end of file
+78510cb5d17d1086a4ab5bd51237496999c175e4
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
index b80c688..9f58f8a 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-a87bb85973b1728f846f9654b519eb9e559ce40c
\ No newline at end of file
+01b2bc107d7e21e39878883e67a5d03e10dcfa69
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
index 9125fad93..6febb5a 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-e367f6f091aae3a3c08f58ae3309a70fa1379540
\ No newline at end of file
+0331de45becdf3fc48b80a350551ff5ed40fb0c0
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
index 402d538..9a2ee90 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-df97d64ccae429ce9d3aad6d97e62220ba644902
\ No newline at end of file
+1728e1c4387fde80141a803bdf7799029b7b6e1f
\ No newline at end of file
diff --git a/ios/web/navigation/crw_wk_navigation_handler.mm b/ios/web/navigation/crw_wk_navigation_handler.mm
index 1ae2b83..5413d66c 100644
--- a/ios/web/navigation/crw_wk_navigation_handler.mm
+++ b/ios/web/navigation/crw_wk_navigation_handler.mm
@@ -1584,8 +1584,8 @@
   if (action.navigationType == WKNavigationTypeFormResubmitted) {
     return web::FormWarningType::kRepost;
   }
-  if (base::FeatureList::IsEnabled(security_interstitials::features::
-                                       kInsecureFormSubmissionInterstitial) &&
+  if (web::GetWebClient()->IsInsecureFormWarningEnabled(
+          self.webStateImpl->GetBrowserState()) &&
       action.navigationType == WKNavigationTypeFormSubmitted) {
     if (action.sourceFrame) {
       GURL source_url = web::GURLOriginWithWKSecurityOrigin(
diff --git a/ios/web/public/web_client.h b/ios/web/public/web_client.h
index e7dafe6..3de5224 100644
--- a/ios/web/public/web_client.h
+++ b/ios/web/public/web_client.h
@@ -193,6 +193,9 @@
   // set.
   virtual void SetOSLockdownModeEnabled(web::BrowserState* browser_state,
                                         bool enabled);
+
+  virtual bool IsInsecureFormWarningEnabled(
+      web::BrowserState* browser_state) const;
 };
 
 }  // namespace web
diff --git a/ios/web/web_client.mm b/ios/web/web_client.mm
index 2af277f..9b927c9 100644
--- a/ios/web/web_client.mm
+++ b/ios/web/web_client.mm
@@ -126,4 +126,9 @@
 void WebClient::SetOSLockdownModeEnabled(web::BrowserState* browser_state,
                                          bool enabled) {}
 
+bool WebClient::IsInsecureFormWarningEnabled(
+    web::BrowserState* browser_state) const {
+  return true;
+}
+
 }  // namespace web
diff --git a/ios/web_view/internal/web_view_web_client.h b/ios/web_view/internal/web_view_web_client.h
index d6b71e6..2a36a65 100644
--- a/ios/web_view/internal/web_view_web_client.h
+++ b/ios/web_view/internal/web_view_web_client.h
@@ -45,6 +45,8 @@
   bool EnableWebInspector(web::BrowserState* browser_state) const override;
   bool IsMixedContentAutoupgradeEnabled(
       web::BrowserState* browser_state) const override;
+  bool IsInsecureFormWarningEnabled(
+      web::BrowserState* browser_state) const override;
 };
 
 }  // namespace ios_web_view
diff --git a/ios/web_view/internal/web_view_web_client.mm b/ios/web_view/internal/web_view_web_client.mm
index 74df222..136c3231 100644
--- a/ios/web_view/internal/web_view_web_client.mm
+++ b/ios/web_view/internal/web_view_web_client.mm
@@ -183,4 +183,12 @@
       security_interstitials::features::kMixedContentAutoupgrade);
 }
 
+bool WebViewWebClient::IsInsecureFormWarningEnabled(
+    web::BrowserState* browser_state) const {
+  // ios/web_view doesn't receive variations seeds at runtime, so this will
+  // only ever use the default value of the feature.
+  return base::FeatureList::IsEnabled(
+      security_interstitials::features::kInsecureFormSubmissionInterstitial);
+}
+
 }  // namespace ios_web_view
diff --git a/ios_internal b/ios_internal
index f94bc05..5efd774 160000
--- a/ios_internal
+++ b/ios_internal
@@ -1 +1 @@
-Subproject commit f94bc05bf5ee979b36eb2d58b336e469404524c1
+Subproject commit 5efd774964ac708dfd7625fc954f8c70391c79e6
diff --git a/media/gpu/v4l2/BUILD.gn b/media/gpu/v4l2/BUILD.gn
index 8a0cc82..e07f8c6f 100644
--- a/media/gpu/v4l2/BUILD.gn
+++ b/media/gpu/v4l2/BUILD.gn
@@ -112,6 +112,7 @@
   deps = [
     ":v4l2_status",
     "//base",
+    "//build/config/linux/libdrm",
     "//gpu/command_buffer/service:gles2",
     "//gpu/ipc/common",
     "//gpu/ipc/service",
diff --git a/media/gpu/v4l2/v4l2_video_decoder.cc b/media/gpu/v4l2/v4l2_video_decoder.cc
index 6f24d49..0085049 100644
--- a/media/gpu/v4l2/v4l2_video_decoder.cc
+++ b/media/gpu/v4l2/v4l2_video_decoder.cc
@@ -4,6 +4,8 @@
 
 #include "media/gpu/v4l2/v4l2_video_decoder.h"
 
+#include <drm_fourcc.h>
+
 #include <algorithm>
 
 #include "base/containers/contains.h"
@@ -736,7 +738,7 @@
     }
 
     VLOGF(1) << "buffer modifier: " << std::hex << layout->modifier();
-    if (layout->modifier() &&
+    if (layout->modifier() != DRM_FORMAT_MOD_LINEAR &&
         layout->modifier() != gfx::NativePixmapHandle::kNoModifier) {
       absl::optional<struct v4l2_format> modifier_format =
           output_queue_->SetModifierFormat(layout->modifier(), picked_size);
diff --git a/media/gpu/vaapi/vaapi_video_encode_accelerator.cc b/media/gpu/vaapi/vaapi_video_encode_accelerator.cc
index 5003c0b7..e66f64f 100644
--- a/media/gpu/vaapi/vaapi_video_encode_accelerator.cc
+++ b/media/gpu/vaapi/vaapi_video_encode_accelerator.cc
@@ -23,6 +23,7 @@
 #include "base/memory/shared_memory_mapping.h"
 #include "base/memory/unsafe_shared_memory_region.h"
 #include "base/numerics/safe_conversions.h"
+#include "base/strings/strcat.h"
 #include "base/strings/stringprintf.h"
 #include "base/task/bind_post_task.h"
 #include "base/task/sequenced_task_runner.h"
@@ -367,7 +368,8 @@
   DCHECK_GT(ave_config.max_num_ref_frames, 0u);
   if (!encoder_->Initialize(config, ave_config)) {
     NotifyError({EncoderStatus::Codes::kEncoderInitializationError,
-                 "Failed initializing encoder"});
+                 base::StrCat({"Failed initializing encoder. config: ",
+                               config.AsHumanReadableString()})});
     return;
   }
 
@@ -389,7 +391,8 @@
       num_frames_in_flight_ * std::max<size_t>(1, config.spatial_layers.size());
   if (!vaapi_wrapper_->CreateContext(encoder_->GetCodedSize())) {
     NotifyError({EncoderStatus::Codes::kEncoderInitializationError,
-                 "Failed creating VAContext"});
+                 base::StrCat({"Failed creating VAContext. config: ",
+                               config.AsHumanReadableString()})});
     return;
   }
 
diff --git a/mojo/public/tools/bindings/README.md b/mojo/public/tools/bindings/README.md
index 6f05eae..717d778c 100644
--- a/mojo/public/tools/bindings/README.md
+++ b/mojo/public/tools/bindings/README.md
@@ -908,7 +908,7 @@
 
 ModuleStatement = AttributeSection "module" Identifier ";"
 ImportStatement = "import" StringLiteral ";"
-Definition = Struct Union Interface Enum Const
+Definition = Struct Union Interface Enum Feature Const
 
 AttributeSection = <empty> | "[" AttributeList "]"
 AttributeList = <empty> | NonEmptyAttributeList
@@ -973,6 +973,13 @@
           | AttributeSection Name "=" Integer
           | AttributeSection Name "=" Identifier
 
+; Note: `feature` is a weak keyword and can appear as, say, a struct field name.
+Feature = AttributeSection "feature" Name "{" FeatureBody "}" ";"
+       | AttributeSection "feature" Name ";"
+FeatureBody = <empty>
+           | FeatureBody FeatureField
+FeatureField = AttributeSection TypeSpec Name Default ";"
+
 Const = "const" TypeSpec Name "=" Constant ";"
 
 Constant = Literal | Identifier ";"
diff --git a/net/nqe/network_qualities_prefs_manager_unittest.cc b/net/nqe/network_qualities_prefs_manager_unittest.cc
index 58917b6..3a627bc 100644
--- a/net/nqe/network_qualities_prefs_manager_unittest.cc
+++ b/net/nqe/network_qualities_prefs_manager_unittest.cc
@@ -251,9 +251,7 @@
   // NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN.
   EXPECT_LE(kMaxCacheSize - 1, count_2g_entries);
 
-  base::HistogramTester histogram_tester;
   estimator.OnPrefsRead(read_prefs);
-  histogram_tester.ExpectUniqueSample("NQE.Prefs.ReadSize", kMaxCacheSize, 1);
 
   manager.ShutdownOnPrefSequence();
 }
diff --git a/net/nqe/network_quality_estimator.cc b/net/nqe/network_quality_estimator.cc
index 8d9ade2a..717a1a4 100644
--- a/net/nqe/network_quality_estimator.cc
+++ b/net/nqe/network_quality_estimator.cc
@@ -1285,7 +1285,6 @@
                    nqe::internal::CachedNetworkQuality> read_prefs) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  UMA_HISTOGRAM_COUNTS_1M("NQE.Prefs.ReadSize", read_prefs.size());
   for (auto& it : read_prefs) {
     EffectiveConnectionType effective_connection_type =
         it.second.effective_connection_type();
diff --git a/net/nqe/network_quality_estimator_unittest.cc b/net/nqe/network_quality_estimator_unittest.cc
index 2b79481..203993c8 100644
--- a/net/nqe/network_quality_estimator_unittest.cc
+++ b/net/nqe/network_quality_estimator_unittest.cc
@@ -2253,7 +2253,6 @@
 
 // Verify that the cached network qualities from the prefs are correctly used.
 TEST_F(NetworkQualityEstimatorTest, OnPrefsRead) {
-  base::HistogramTester histogram_tester;
 
   // Construct the read prefs.
   std::map<nqe::internal::NetworkID, nqe::internal::CachedNetworkQuality>
@@ -2296,8 +2295,6 @@
 
   // Simulate reading of prefs.
   estimator.OnPrefsRead(read_prefs);
-  histogram_tester.ExpectUniqueSample("NQE.Prefs.ReadSize", read_prefs.size(),
-                                      1);
 
   // Taken from network_quality_estimator_params.cc.
   EXPECT_EQ(base::Milliseconds(1800),
@@ -2358,7 +2355,6 @@
 // Verify that the cached network qualities from the prefs are not used if the
 // reading of the network quality prefs is not enabled..
 TEST_F(NetworkQualityEstimatorTest, OnPrefsReadWithReadingDisabled) {
-  base::HistogramTester histogram_tester;
 
   // Construct the read prefs.
   std::map<nqe::internal::NetworkID, nqe::internal::CachedNetworkQuality>
@@ -2402,8 +2398,6 @@
 
   // Simulate reading of prefs.
   estimator.OnPrefsRead(read_prefs);
-  histogram_tester.ExpectUniqueSample("NQE.Prefs.ReadSize", read_prefs.size(),
-                                      1);
 
   // Force read the network quality store from the store to verify that store
   // gets populated even if reading of prefs is not enabled.
@@ -2454,7 +2448,6 @@
 // used.
 TEST_F(NetworkQualityEstimatorTest,
        ObservationDiscardedIfCachedEstimateAvailable) {
-  base::HistogramTester histogram_tester;
 
   // Construct the read prefs.
   std::map<nqe::internal::NetworkID, nqe::internal::CachedNetworkQuality>
@@ -2491,8 +2484,6 @@
 
   // Simulate reading of prefs.
   estimator.OnPrefsRead(read_prefs);
-  histogram_tester.ExpectUniqueSample("NQE.Prefs.ReadSize", read_prefs.size(),
-                                      1);
 
   // Taken from network_quality_estimator_params.cc.
   EXPECT_EQ(base::Milliseconds(1800),
diff --git a/services/network/cookie_manager.cc b/services/network/cookie_manager.cc
index 708a4ae..9adc4261 100644
--- a/services/network/cookie_manager.cc
+++ b/services/network/cookie_manager.cc
@@ -194,7 +194,7 @@
       base::BindRepeating(
           [](const DeleteCookiePredicate& predicate,
              const net::CanonicalCookie& cookie) {
-            return predicate.Run(cookie.Domain(), cookie.IsSecure());
+            return predicate.Run(cookie.Domain(), cookie.SourceScheme());
           },
           std::move(delete_cookie_predicate)),
       std::move(callback));
diff --git a/services/network/cookie_settings_unittest.cc b/services/network/cookie_settings_unittest.cc
index bcfe3a6..afc7153 100644
--- a/services/network/cookie_settings_unittest.cc
+++ b/services/network/cookie_settings_unittest.cc
@@ -801,7 +801,8 @@
   settings.set_content_settings(
       ContentSettingsType::COOKIES,
       {CreateSetting("*", "*", CONTENT_SETTING_SESSION_ONLY)});
-  EXPECT_TRUE(settings.CreateDeleteCookieOnExitPredicate().Run(kURL, false));
+  EXPECT_TRUE(settings.CreateDeleteCookieOnExitPredicate().Run(
+      kURL, net::CookieSourceScheme::kNonSecure));
 }
 
 TEST_P(CookieSettingsTest, CreateDeleteCookieOnExitPredicateAllow) {
@@ -810,7 +811,8 @@
       ContentSettingsType::COOKIES,
       {CreateSetting("*", "*", CONTENT_SETTING_ALLOW),
        CreateSetting("*", "*", CONTENT_SETTING_SESSION_ONLY)});
-  EXPECT_FALSE(settings.CreateDeleteCookieOnExitPredicate().Run(kURL, false));
+  EXPECT_FALSE(settings.CreateDeleteCookieOnExitPredicate().Run(
+      kURL, net::CookieSourceScheme::kNonSecure));
 }
 
 TEST_P(CookieSettingsTest, GetCookieSettingSecureOriginCookiesAllowed) {
diff --git a/services/network/masked_domain_list/network_service_proxy_allow_list.cc b/services/network/masked_domain_list/network_service_proxy_allow_list.cc
index c213b8e..9b13f02 100644
--- a/services/network/masked_domain_list/network_service_proxy_allow_list.cc
+++ b/services/network/masked_domain_list/network_service_proxy_allow_list.cc
@@ -4,6 +4,7 @@
 //
 #include "services/network/masked_domain_list/network_service_proxy_allow_list.h"
 
+#include "base/containers/contains.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/trace_event/memory_usage_estimator.h"
 #include "components/privacy_sandbox/masked_domain_list/masked_domain_list.pb.h"
@@ -109,15 +110,34 @@
 
 void NetworkServiceProxyAllowList::UseMaskedDomainList(
     const masked_domain_list::MaskedDomainList& mdl) {
+  const int experiment_group_id =
+      network::features::kMaskedDomainListExperimentGroup.Get();
+
+  // Clients are in the default group if the experiment_group_id is the feature
+  // default value of 0.
+  const bool in_default_group = experiment_group_id == 0;
+
+  // All Resources are used by the default group unless they are explicitly
+  // excluded. For a client in the experiment group to use a Resource, the
+  // Resource must explicitly list the experiment group.
+  auto is_eligible = [&](masked_domain_list::Resource resource) {
+    if (in_default_group) {
+      return !resource.exclude_default_group();
+    }
+    return base::Contains(resource.experiment_group_ids(), experiment_group_id);
+  };
+
   url_matcher_with_bypass_.Clear();
   for (auto owner : mdl.resource_owners()) {
     // Group domains by partition first so that only one set of the owner's
     // bypass rules are created per partition.
     std::map<std::string, std::vector<std::string>> owned_domains_by_partition;
     for (auto resource : owner.owned_resources()) {
-      const std::string partition =
-          UrlMatcherWithBypass::PartitionMapKey(resource.domain());
-      owned_domains_by_partition[partition].emplace_back(resource.domain());
+      if (is_eligible(resource)) {
+        const std::string partition =
+            UrlMatcherWithBypass::PartitionMapKey(resource.domain());
+        owned_domains_by_partition[partition].emplace_back(resource.domain());
+      }
     }
 
     for (const auto& [partition, domains] : owned_domains_by_partition) {
diff --git a/services/network/masked_domain_list/network_service_proxy_allow_list_unittest.cc b/services/network/masked_domain_list/network_service_proxy_allow_list_unittest.cc
index e18ba60..485c4d4c 100644
--- a/services/network/masked_domain_list/network_service_proxy_allow_list_unittest.cc
+++ b/services/network/masked_domain_list/network_service_proxy_allow_list_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "services/network/masked_domain_list/network_service_proxy_allow_list.h"
 
+#include "base/strings/strcat.h"
 #include "base/test/scoped_feature_list.h"
 #include "components/privacy_sandbox/masked_domain_list/masked_domain_list.pb.h"
 #include "net/base/network_anonymization_key.h"
@@ -17,13 +18,67 @@
 namespace {
 using masked_domain_list::MaskedDomainList;
 
-struct MatchTest {
+struct ExperimentGroupMatchTest {
   std::string name;
   std::string req;
   std::string top;
+  // The proto has an int type but feature init needs a string representation.
+  std::string experiment_group;
   bool matches;
 };
 
+const std::vector<ExperimentGroupMatchTest> kMatchTests = {
+    ExperimentGroupMatchTest{
+        "NoExperimentGroup_ExcludedFromResource",
+        "experiment.com",
+        "top.com",
+        "0",
+        false,
+    },
+    ExperimentGroupMatchTest{
+        "NoExperimentGroup_DefaultResourceMatch",
+        "example.com",
+        "top.com",
+        "0",
+        true,
+    },
+    ExperimentGroupMatchTest{
+        "ExperimentGroup1_ExperimentResourceMatch",
+        "experiment.com",
+        "top.com",
+        "1",
+        true,
+    },
+    ExperimentGroupMatchTest{
+        "ExperimentGroup2_ExperimentResourceMatch",
+        "experiment.com",
+        "top.com",
+        "2",
+        true,
+    },
+    ExperimentGroupMatchTest{
+        "ExperimentGroup1_DefaultResourceMatch",
+        "example.com",
+        "top.com",
+        "1",
+        true,
+    },
+    ExperimentGroupMatchTest{
+        "ExperimentGroup2_ExcludedFromDefaultResource",
+        "example.com",
+        "top.com",
+        "2",
+        false,
+    },
+    ExperimentGroupMatchTest{
+        "ExperimentGroup3_ExcludedFromDefaultResource",
+        "experiment.com",
+        "top.com",
+        "3",
+        false,
+    },
+};
+
 }  // namespace
 
 class NetworkServiceProxyAllowListTest : public ::testing::Test {};
@@ -203,4 +258,61 @@
       GURL("https://example.com"),
       net::NetworkAnonymizationKey::CreateTransient()));
 }
+
+class NetworkServiceProxyAllowListExperimentGroupMatchTest
+    : public testing::TestWithParam<ExperimentGroupMatchTest> {};
+
+TEST_P(NetworkServiceProxyAllowListExperimentGroupMatchTest, Match) {
+  const ExperimentGroupMatchTest& p = GetParam();
+
+  std::map<std::string, std::string> parameters;
+  parameters[network::features::kMaskedDomainListExperimentGroup.name] =
+      p.experiment_group;
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeatureWithParameters(
+      network::features::kMaskedDomainList, std::move(parameters));
+
+  NetworkServiceProxyAllowList allow_list_no_bypass(
+      network::mojom::IpProtectionProxyBypassPolicy::kNone);
+  NetworkServiceProxyAllowList allow_list_first_party_bypass(
+      network::mojom::IpProtectionProxyBypassPolicy::
+          kFirstPartyToTopLevelFrame);
+
+  MaskedDomainList mdl;
+  auto* resourceOwner = mdl.add_resource_owners();
+  resourceOwner->set_owner_name("example");
+  auto* resource = resourceOwner->add_owned_resources();
+  resource->set_domain("example.com");
+  resource->add_experiment_group_ids(1);
+
+  resourceOwner = mdl.add_resource_owners();
+  resourceOwner->set_owner_name("experiment");
+  resource = resourceOwner->add_owned_resources();
+  resource->set_domain("experiment.com");
+  resource->set_exclude_default_group(true);
+  resource->add_experiment_group_ids(1);
+  resource->add_experiment_group_ids(2);
+
+  allow_list_no_bypass.UseMaskedDomainList(mdl);
+  allow_list_first_party_bypass.UseMaskedDomainList(mdl);
+
+  GURL request_url(base::StrCat({"https://", p.req}));
+  auto network_anonymization_key =
+      net::NetworkAnonymizationKey::CreateCrossSite(
+          net::SchemefulSite(GURL(base::StrCat({"https://", p.top}))));
+
+  EXPECT_EQ(p.matches, allow_list_no_bypass.Matches(request_url,
+                                                    network_anonymization_key));
+  EXPECT_EQ(p.matches, allow_list_no_bypass.Matches(request_url,
+                                                    network_anonymization_key));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    NetworkServiceProxyAllowListExperimentGroupMatchTest,
+    testing::ValuesIn(kMatchTests),
+    [](const testing::TestParamInfo<ExperimentGroupMatchTest>& info) {
+      return info.param.name;
+    });
+
 }  // namespace network
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index 09cd8bb..ae6fef7 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -62,6 +62,7 @@
 #include "net/cert/cert_verifier.h"
 #include "net/cert/coalescing_cert_verifier.h"
 #include "net/cookies/cookie_access_delegate.h"
+#include "net/cookies/cookie_constants.h"
 #include "net/cookies/cookie_monster.h"
 #include "net/cookies/cookie_setting_override.h"
 #include "net/dns/host_cache.h"
@@ -1052,7 +1053,7 @@
 
   auto store_predicate = base::BindRepeating(
       [](DeleteCookiePredicate predicate, const std::string& origin) {
-        return predicate.Run(origin, true);
+        return predicate.Run(origin, net::CookieSourceScheme::kSecure);
       },
       std::move(cookie_predicate));
   trust_token_store_->ExecuteOrEnqueue(base::BindOnce(
diff --git a/services/network/network_qualities_pref_delegate.cc b/services/network/network_qualities_pref_delegate.cc
index 1c70d7b7..2001b9a 100644
--- a/services/network/network_qualities_pref_delegate.cc
+++ b/services/network/network_qualities_pref_delegate.cc
@@ -40,12 +40,10 @@
   void SetDictionaryValue(const base::Value::Dict& dict) override {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     pref_service_->SetDict(path_, dict.Clone());
-    UMA_HISTOGRAM_EXACT_LINEAR("NQE.Prefs.WriteCount", 1, 2);
   }
 
   base::Value::Dict GetDictionaryValue() override {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-    UMA_HISTOGRAM_EXACT_LINEAR("NQE.Prefs.ReadCount", 1, 2);
     return pref_service_->GetDict(path_).Clone();
   }
 
diff --git a/services/network/network_qualities_pref_delegate_unittest.cc b/services/network/network_qualities_pref_delegate_unittest.cc
index 55bef22..20fef2a 100644
--- a/services/network/network_qualities_pref_delegate_unittest.cc
+++ b/services/network/network_qualities_pref_delegate_unittest.cc
@@ -44,45 +44,19 @@
   net::TestNetworkQualityEstimator estimator;
   NetworkQualitiesPrefDelegate::RegisterPrefs(pref_service_simple.registry());
 
-  base::HistogramTester initial_histogram_tester;
   NetworkQualitiesPrefDelegate pref_delegate(&pref_service_simple, &estimator);
-  // NetworkQualityEstimator must be notified of the read prefs at startup.
-  EXPECT_FALSE(
-      initial_histogram_tester.GetAllSamples("NQE.Prefs.ReadSize").empty());
 
-  {
-    base::HistogramTester histogram_tester;
-    estimator.set_effective_connection_type(
-        net::EFFECTIVE_CONNECTION_TYPE_OFFLINE);
-    estimator.set_recent_effective_connection_type(
-        net::EFFECTIVE_CONNECTION_TYPE_OFFLINE);
-    estimator.RunOneRequest();
+  estimator.set_effective_connection_type(
+      net::EFFECTIVE_CONNECTION_TYPE_OFFLINE);
+  estimator.set_recent_effective_connection_type(
+      net::EFFECTIVE_CONNECTION_TYPE_OFFLINE);
+  estimator.RunOneRequest();
 
-    // Prefs are written only if persistent caching was enabled.
-    EXPECT_FALSE(
-        histogram_tester.GetAllSamples("NQE.Prefs.WriteCount").empty());
-    histogram_tester.ExpectTotalCount("NQE.Prefs.ReadCount", 0);
-
-    // NetworkQualityEstimator should not be notified of change in prefs.
-    histogram_tester.ExpectTotalCount("NQE.Prefs.ReadSize", 0);
-  }
-
-  {
-    base::HistogramTester histogram_tester;
-    estimator.set_effective_connection_type(
-        net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
-    estimator.set_recent_effective_connection_type(
-        net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
-    estimator.RunOneRequest();
-
-    // Prefs are written even if the network id was unavailable.
-    EXPECT_FALSE(
-        histogram_tester.GetAllSamples("NQE.Prefs.WriteCount").empty());
-    histogram_tester.ExpectTotalCount("NQE.Prefs.ReadCount", 0);
-
-    // NetworkQualityEstimator should not be notified of change in prefs.
-    histogram_tester.ExpectTotalCount("NQE.Prefs.ReadSize", 0);
-  }
+  estimator.set_effective_connection_type(
+      net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
+  estimator.set_recent_effective_connection_type(
+      net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
+  estimator.RunOneRequest();
 
   // Verify the contents of the prefs by reading them again.
   std::map<net::nqe::internal::NetworkID,
diff --git a/services/network/public/cpp/features.cc b/services/network/public/cpp/features.cc
index 1c61942..6f1e5e7 100644
--- a/services/network/public/cpp/features.cc
+++ b/services/network/public/cpp/features.cc
@@ -112,6 +112,14 @@
              "MaskedDomainList",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// When set, only resources in the MDL that are part of the experiment group
+// will be loaded into the proxy's allow list.
+const base::FeatureParam<int> kMaskedDomainListExperimentGroup{
+    &kMaskedDomainList, /*name=*/"MaskedDomainListExperimentGroup",
+    /*default_value=*/0};
+
+// Used to build the MDL component's installer attributes and possibly control
+// which release version is retrieved. Does not have any effect for WebView.
 const base::FeatureParam<std::string> kMaskedDomainListExperimentalVersion{
     &kMaskedDomainList, /*name=*/"MaskedDomainListExperimentalVersion",
     /*default_value=*/""};
diff --git a/services/network/public/cpp/features.h b/services/network/public/cpp/features.h
index f0a7d348..0d9e77b9 100644
--- a/services/network/public/cpp/features.h
+++ b/services/network/public/cpp/features.h
@@ -33,6 +33,8 @@
 COMPONENT_EXPORT(NETWORK_CPP) BASE_DECLARE_FEATURE(kDnsOverHttpsUpgrade);
 COMPONENT_EXPORT(NETWORK_CPP) BASE_DECLARE_FEATURE(kMaskedDomainList);
 COMPONENT_EXPORT(NETWORK_CPP)
+extern const base::FeatureParam<int> kMaskedDomainListExperimentGroup;
+COMPONENT_EXPORT(NETWORK_CPP)
 extern const base::FeatureParam<std::string>
     kMaskedDomainListExperimentalVersion;
 COMPONENT_EXPORT(NETWORK_CPP)
diff --git a/services/network/public/cpp/session_cookie_delete_predicate.h b/services/network/public/cpp/session_cookie_delete_predicate.h
index 5d98d24..1937537 100644
--- a/services/network/public/cpp/session_cookie_delete_predicate.h
+++ b/services/network/public/cpp/session_cookie_delete_predicate.h
@@ -8,15 +8,15 @@
 #include <string>
 
 #include "base/functional/callback_forward.h"
+#include "net/cookies/cookie_constants.h"
 
 namespace network {
 // A DeleteCookiePredicate callback function decides if the cookie associated
 // with the domain and is_https status should be deleted on exit, and is used
 // when creating a cookie storage policy. It has two parameters, the first one
-// is the domain of a cookie and the second one is a bool which represents
-// whether the cookie is secure as parameters.
+// is the domain of a cookie and the second one is the scheme of the domain.
 using DeleteCookiePredicate =
-    base::RepeatingCallback<bool(const std::string&, bool)>;
+    base::RepeatingCallback<bool(const std::string&, net::CookieSourceScheme)>;
 
 }  // namespace network
 
diff --git a/services/network/session_cleanup_cookie_store.cc b/services/network/session_cleanup_cookie_store.cc
index f9f8323..7308e5c5 100644
--- a/services/network/session_cleanup_cookie_store.cc
+++ b/services/network/session_cleanup_cookie_store.cc
@@ -62,7 +62,10 @@
     const GURL url(
         net::cookie_util::CookieOriginToURL(cookie.first, cookie.second));
     if (!url.is_valid() ||
-        !delete_cookie_predicate.Run(cookie.first, cookie.second)) {
+        !delete_cookie_predicate.Run(
+            cookie.first, cookie.second
+                              ? net::CookieSourceScheme::kSecure
+                              : net::CookieSourceScheme::kNonSecure)) {
       continue;
     }
     net_log_.AddEvent(
@@ -94,8 +97,8 @@
 }
 
 void SessionCleanupCookieStore::AddCookie(const net::CanonicalCookie& cc) {
-  net::SQLitePersistentCookieStore::CookieOrigin origin(cc.Domain(),
-                                                        cc.IsSecure());
+  net::SQLitePersistentCookieStore::CookieOrigin origin(
+      cc.Domain(), cc.SourceScheme() == net::CookieSourceScheme::kSecure);
   ++cookies_per_origin_[origin];
   persistent_store_->AddCookie(cc);
 }
@@ -106,8 +109,8 @@
 }
 
 void SessionCleanupCookieStore::DeleteCookie(const net::CanonicalCookie& cc) {
-  net::SQLitePersistentCookieStore::CookieOrigin origin(cc.Domain(),
-                                                        cc.IsSecure());
+  net::SQLitePersistentCookieStore::CookieOrigin origin(
+      cc.Domain(), cc.SourceScheme() == net::CookieSourceScheme::kSecure);
   DCHECK_GE(cookies_per_origin_[origin], 1U);
   --cookies_per_origin_[origin];
   persistent_store_->DeleteCookie(cc);
@@ -130,8 +133,9 @@
     LoadedCallback loaded_callback,
     std::vector<std::unique_ptr<net::CanonicalCookie>> cookies) {
   for (const auto& cookie : cookies) {
-    net::SQLitePersistentCookieStore::CookieOrigin origin(cookie->Domain(),
-                                                          cookie->IsSecure());
+    net::SQLitePersistentCookieStore::CookieOrigin origin(
+        cookie->Domain(),
+        cookie->SourceScheme() == net::CookieSourceScheme::kSecure);
     ++cookies_per_origin_[origin];
   }
 
diff --git a/services/network/session_cleanup_cookie_store_unittest.cc b/services/network/session_cleanup_cookie_store_unittest.cc
index 5d14ef71..d66a79c6 100644
--- a/services/network/session_cleanup_cookie_store_unittest.cc
+++ b/services/network/session_cleanup_cookie_store_unittest.cc
@@ -138,8 +138,8 @@
   AddCookie("A", "B", "nonpersistent.com", "/", t);
 
   // Cookies from "nonpersistent.com" should be deleted.
-  store_->DeleteSessionCookies(
-      base::BindRepeating([](const std::string& domain, bool is_https) {
+  store_->DeleteSessionCookies(base::BindRepeating(
+      [](const std::string& domain, net::CookieSourceScheme scheme) {
         return domain == "nonpersistent.com";
       }));
   DestroyStore();
@@ -165,8 +165,8 @@
 
   net_log_observer_.SetObserverCaptureMode(net::NetLogCaptureMode::kDefault);
   // Cookies from "nonpersistent.com" should be deleted.
-  store_->DeleteSessionCookies(
-      base::BindRepeating([](const std::string& domain, bool is_https) {
+  store_->DeleteSessionCookies(base::BindRepeating(
+      [](const std::string& domain, net::CookieSourceScheme scheme) {
         return domain == "nonpersistent.com";
       }));
   DestroyStore();
@@ -210,8 +210,8 @@
   AddCookie("A", "B", "nonpersistent.com", "/second", t);
 
   // Cookies from "nonpersistent.com" should be deleted.
-  store_->DeleteSessionCookies(
-      base::BindRepeating([](const std::string& domain, bool is_https) {
+  store_->DeleteSessionCookies(base::BindRepeating(
+      [](const std::string& domain, net::CookieSourceScheme scheme) {
         return domain == "nonpersistent.com";
       }));
   task_environment_.RunUntilIdle();
@@ -248,8 +248,8 @@
 
   store_->SetForceKeepSessionState();
   // Cookies from "nonpersistent.com" should NOT be deleted.
-  store_->DeleteSessionCookies(
-      base::BindRepeating([](const std::string& domain, bool is_https) {
+  store_->DeleteSessionCookies(base::BindRepeating(
+      [](const std::string& domain, net::CookieSourceScheme scheme) {
         return domain == "nonpersistent.com";
       }));
   task_environment_.RunUntilIdle();
diff --git a/services/on_device_model/ml/chrome_ml.cc b/services/on_device_model/ml/chrome_ml.cc
index 9527203..7ffc7cb5 100644
--- a/services/on_device_model/ml/chrome_ml.cc
+++ b/services/on_device_model/ml/chrome_ml.cc
@@ -58,7 +58,7 @@
 }
 
 void FatalErrorFn(const char* msg) {
-  SCOPED_CRASH_KEY_STRING256("ChromeML", "error_msg", msg);
+  SCOPED_CRASH_KEY_STRING1024("ChromeML", "error_msg", msg);
   CHECK(false) << "ChromeML Error: " << msg;
 }
 
diff --git a/services/on_device_model/public/cpp/model_assets.h b/services/on_device_model/public/cpp/model_assets.h
index 5f2daa9..5d6879ad 100644
--- a/services/on_device_model/public/cpp/model_assets.h
+++ b/services/on_device_model/public/cpp/model_assets.h
@@ -17,6 +17,11 @@
   ModelAssetPaths(const ModelAssetPaths&);
   ~ModelAssetPaths();
 
+  // Returns whether the required models to determine text safety are set.
+  bool HasSafetyFiles() const {
+    return !ts_data.empty() && !ts_sp_model.empty();
+  }
+
   base::FilePath sp_model;
   base::FilePath model;
   base::FilePath weights;
diff --git a/testing/buildbot/filters/android.emulator_12l.chrome_public_test_apk.filter b/testing/buildbot/filters/android.emulator_12l.chrome_public_test_apk.filter
index fb8aea67..35d1db5e 100644
--- a/testing/buildbot/filters/android.emulator_12l.chrome_public_test_apk.filter
+++ b/testing/buildbot/filters/android.emulator_12l.chrome_public_test_apk.filter
@@ -91,3 +91,32 @@
 
 # crbug.com/1432785
 -org.chromium.chrome.browser.ContentViewFocusTest.testHideSelectionOnPhoneTabSwiping
+
+# crbug.com/1511801
+-org.chromium.chrome.browser.app.bookmarks.BookmarkTest.testEmptyBookmarkFolder
+-org.chromium.chrome.browser.app.bookmarks.BookmarkTest.testEmptyReadingListFolder
+-org.chromium.chrome.browser.app.bookmarks.BookmarkTest.testOpenBookmarkManagerFolder
+
+# crbug.com/1511804
+-org.chromium.chrome.browser.tasks.tab_management.SelectableTabListEditorTest.testToolbarMenuItem_GroupActionAndUndo
+-org.chromium.chrome.browser.tasks.tab_management.SelectableTabListEditorTest.testToolbarMenuItem_ShareActionGroupsOnly
+-org.chromium.chrome.browser.tasks.tab_management.SelectableTabListEditorTest.testToolbarMenuItem_ShareActionView
+-org.chromium.chrome.browser.tasks.tab_management.SelectableTabListEditorTest.testUndoToolbarGroup
+
+# crbug.com/1512248
+-org.chromium.chrome.browser.tasks.tab_management.TabGridDialogTest.testDialogSelectionEditor_PostLongPressClickNoSelectionEditor
+-org.chromium.chrome.browser.tasks.tab_management.TabGridDialogTest.testDialogSelectionEditor_ShareActionTabs
+-org.chromium.chrome.browser.tasks.tab_management.TabGridDialogTest.testDialogSelectionEditor_ShareActionView
+
+# crbug.com/1512250
+-org.chromium.chrome.browser.tasks.tab_management.TabSwitcherTabletTest.testEmptyStateView_ToggleIncognito
+-org.chromium.chrome.browser.tasks.tab_management.TabSwitcherTabletTest.testGridTabSwitcherOnCloseAllTabs
+
+# crbug.com/1512251
+-org.chromium.chrome.browser.incognito.IncognitoStorageLeakageTest.testStorageDoesNotLeakFromActivityToActivity__REGULAR_CCT_INCOGNITO_CCT
+-org.chromium.chrome.browser.incognito.IncognitoStorageLeakageTest.testStorageDoesNotLeakFromActivityToActivity__REGULAR_CCT_REGULAR_CCT
+-org.chromium.chrome.browser.incognito.IncognitoStorageLeakageTest.testStorageDoesNotLeakFromActivityToActivity__REGULAR_CCT_REGULAR_TAB
+
+# crbug.com/1512916
+-org.chromium.chrome.browser.gesturenav.NavigationHandlerTest.testCloseChromeAtHistoryStackHead
+-org.chromium.chrome.browser.gesturenav.NavigationHandlerTest.testSwipeNavigateOnNativePage
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index f90261559..1f967a0 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -4645,7 +4645,8 @@
                     },
                     "enable_features": [
                         "AttributionDebugReportingCookieDeprecationTesting",
-                        "CookieDeprecationFacilitatedTesting"
+                        "CookieDeprecationFacilitatedTesting",
+                        "FledgeFacilitatedTestingSignalsHeaders"
                     ]
                 }
             ]
diff --git a/third_party/blink/public/common/origin_trials/trial_token.h b/third_party/blink/public/common/origin_trials/trial_token.h
index f4f6e20..12755f4 100644
--- a/third_party/blink/public/common/origin_trials/trial_token.h
+++ b/third_party/blink/public/common/origin_trials/trial_token.h
@@ -18,8 +18,6 @@
 
 namespace blink {
 
-// The enum entries below are written to histograms and thus cannot be deleted
-// or reordered.
 // New entries must be added immediately before the end.
 enum class OriginTrialTokenStatus {
   kSuccess = 0,
diff --git a/third_party/blink/renderer/bindings/core/v8/activity_logger_test.cc b/third_party/blink/renderer/bindings/core/v8/activity_logger_test.cc
index 37ebb4a..abd1d9f 100644
--- a/third_party/blink/renderer/bindings/core/v8/activity_logger_test.cc
+++ b/third_party/blink/renderer/bindings/core/v8/activity_logger_test.cc
@@ -119,8 +119,7 @@
  private:
   static const int kIsolatedWorldId = 1;
 
-  test::TaskEnvironment task_environment_{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment_;
   WebViewHelper web_view_helper_;
   Persistent<LocalFrame> local_frame_;
   // TestActivityLogger is owned by a static table within V8DOMActivityLogger
diff --git a/third_party/blink/renderer/bindings/core/v8/script_promise_property_test.cc b/third_party/blink/renderer/bindings/core/v8/script_promise_property_test.cc
index 5963b4cd..3665fd5 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_promise_property_test.cc
+++ b/third_party/blink/renderer/bindings/core/v8/script_promise_property_test.cc
@@ -178,8 +178,7 @@
   }
 
  private:
-  test::TaskEnvironment task_environment_{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment_;
   std::unique_ptr<DummyPageHolder> page_;
   Persistent<ScriptState> other_script_state_;
 };
diff --git a/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc b/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc
index 6111e987..dd4c511 100644
--- a/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc
+++ b/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc
@@ -189,8 +189,7 @@
     0x2d, 0x0a};
 
 TEST(V8ScriptValueSerializerForModulesTest, RoundTripRTCCertificate) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   // If WebRTC is not supported in this build, this test is meaningless.
   std::unique_ptr<RTCCertificateGenerator> certificate_generator =
       std::make_unique<RTCCertificateGenerator>();
@@ -221,8 +220,7 @@
 }
 
 TEST(V8ScriptValueSerializerForModulesTest, DecodeRTCCertificate) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   // If WebRTC is not supported in this build, this test is meaningless.
   std::unique_ptr<RTCCertificateGenerator> certificate_generator =
       std::make_unique<RTCCertificateGenerator>();
@@ -250,8 +248,7 @@
 }
 
 TEST(V8ScriptValueSerializerForModulesTest, DecodeInvalidRTCCertificate) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
 
   // This is valid, except that "private" is not a valid private key PEM and
@@ -447,8 +444,7 @@
 
 // AES-128-CBC uses AES key params.
 TEST(V8ScriptValueSerializerForModulesTest, RoundTripCryptoKeyAES) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope(KURL("https://secure.context/"));
   ScriptState* script_state = scope.GetScriptState();
 
@@ -490,8 +486,7 @@
 }
 
 TEST(V8ScriptValueSerializerForModulesTest, DecodeCryptoKeyAES) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope(KURL("https://secure.context/"));
   ScriptState* script_state = scope.GetScriptState();
 
@@ -521,8 +516,7 @@
 
 // HMAC-SHA256 uses HMAC key params.
 TEST(V8ScriptValueSerializerForModulesTest, RoundTripCryptoKeyHMAC) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope(KURL("https://secure.context/"));
   ScriptState* script_state = scope.GetScriptState();
 
@@ -563,8 +557,7 @@
 }
 
 TEST(V8ScriptValueSerializerForModulesTest, DecodeCryptoKeyHMAC) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope(KURL("https://secure.context/"));
   ScriptState* script_state = scope.GetScriptState();
 
@@ -598,8 +591,7 @@
 
 // RSA-PSS-SHA256 uses RSA hashed key params.
 TEST(V8ScriptValueSerializerForModulesTest, RoundTripCryptoKeyRSAHashed) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope(KURL("https://secure.context/"));
   ScriptState* script_state = scope.GetScriptState();
 
@@ -643,8 +635,7 @@
 }
 
 TEST(V8ScriptValueSerializerForModulesTest, DecodeCryptoKeyRSAHashed) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope(KURL("https://secure.context/"));
   ScriptState* script_state = scope.GetScriptState();
 
@@ -696,8 +687,7 @@
 
 // ECDSA uses EC key params.
 TEST(V8ScriptValueSerializerForModulesTest, RoundTripCryptoKeyEC) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope(KURL("https://secure.context/"));
   ScriptState* script_state = scope.GetScriptState();
 
@@ -741,8 +731,7 @@
 }
 
 TEST(V8ScriptValueSerializerForModulesTest, DecodeCryptoKeyEC) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope(KURL("https://secure.context/"));
   ScriptState* script_state = scope.GetScriptState();
 
@@ -785,8 +774,7 @@
 
 // Ed25519 uses no params.
 TEST(V8ScriptValueSerializerForModulesTest, RoundTripCryptoKeyEd25519) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope(KURL("https://secure.context/"));
   ScriptState* script_state = scope.GetScriptState();
 
@@ -828,8 +816,7 @@
 
 // Ed25519 uses no params.
 TEST(V8ScriptValueSerializerForModulesTest, DecodeCryptoKeyEd25519) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope(KURL("https://secure.context/"));
   ScriptState* script_state = scope.GetScriptState();
 
@@ -867,8 +854,7 @@
 }
 
 TEST(V8ScriptValueSerializerForModulesTest, RoundTripCryptoKeyX25519) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope(KURL("https://secure.context/"));
   ScriptState* script_state = scope.GetScriptState();
 
@@ -910,8 +896,7 @@
 }
 
 TEST(V8ScriptValueSerializerForModulesTest, DecodeCryptoKeyX25519) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope(KURL("https://secure.context/"));
   ScriptState* script_state = scope.GetScriptState();
 
@@ -962,8 +947,7 @@
 }
 
 TEST(V8ScriptValueSerializerForModulesTest, RoundTripCryptoKeyNoParams) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope(KURL("https://secure.context/"));
   ScriptState* script_state = scope.GetScriptState();
 
@@ -997,8 +981,7 @@
 }
 
 TEST(V8ScriptValueSerializerForModulesTest, DecodeCryptoKeyNoParams) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope(KURL("https://secure.context/"));
   ScriptState* script_state = scope.GetScriptState();
 
@@ -1027,8 +1010,7 @@
 }
 
 TEST(V8ScriptValueSerializerForModulesTest, DecodeCryptoKeyInvalid) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope(KURL("https://secure.context/"));
   ScriptState* script_state = scope.GetScriptState();
 
@@ -1150,8 +1132,7 @@
 }
 
 TEST(V8ScriptValueSerializerForModulesTest, RoundTripDOMFileSystem) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
 
   auto* fs = MakeGarbageCollected<DOMFileSystem>(
@@ -1173,8 +1154,7 @@
 }
 
 TEST(V8ScriptValueSerializerForModulesTest, RoundTripDOMFileSystemNotClonable) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   ExceptionState exception_state(scope.GetIsolate(),
                                  ExceptionContextType::kOperationInvoke,
@@ -1193,8 +1173,7 @@
 }
 
 TEST(V8ScriptValueSerializerForModulesTest, DecodeDOMFileSystem) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
 
   // This is encoded data generated from Chromium (around M56).
@@ -1221,8 +1200,7 @@
 }
 
 TEST(V8ScriptValueSerializerForModulesTest, DecodeInvalidDOMFileSystem) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   ScriptState* script_state = scope.GetScriptState();
 
@@ -1246,8 +1224,7 @@
 }
 
 TEST(V8ScriptValueSerializerForModulesTest, RoundTripVideoFrame) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
 
   const gfx::Size kFrameSize(600, 480);
@@ -1277,8 +1254,7 @@
 }
 
 TEST(V8ScriptValueSerializerForModulesTest, TransferVideoFrame) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
 
   const gfx::Size kFrameSize(600, 480);
@@ -1312,8 +1288,7 @@
 }
 
 TEST(V8ScriptValueSerializerForModulesTest, ClosedVideoFrameThrows) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   ExceptionState exception_state(scope.GetIsolate(),
                                  ExceptionContextType::kOperationInvoke,
@@ -1337,8 +1312,7 @@
 }
 
 TEST(V8ScriptValueSerializerForModulesTest, RoundTripAudioData) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
 
   const unsigned kChannels = 2;
@@ -1404,8 +1378,7 @@
 }
 
 TEST(V8ScriptValueSerializerForModulesTest, TransferAudioData) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
 
   const unsigned kFrames = 500;
@@ -1440,8 +1413,7 @@
 }
 
 TEST(V8ScriptValueSerializerForModulesTest, ClosedAudioDataThrows) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   ExceptionState exception_state(scope.GetIsolate(),
                                  ExceptionContextType::kOperationInvoke,
@@ -1466,8 +1438,7 @@
 }
 
 TEST(V8ScriptValueSerializerForModulesTest, TransferMediaStreamTrack) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   // This flag is default-off for Android, so we force it on to test this
   // functionality.
   ScopedRegionCaptureForTest region_capture(true);
@@ -1520,8 +1491,7 @@
 
 TEST(V8ScriptValueSerializerForModulesTest,
      TransferMediaStreamTrackRegionCaptureDisabled) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   // Test with region capture disabled, since this is the default for Android.
   ScopedRegionCaptureForTest region_capture(false);
   V8TestingScope scope;
@@ -1553,8 +1523,7 @@
 }
 
 TEST(V8ScriptValueSerializerForModulesTest, TransferAudioMediaStreamTrack) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
 
   const auto session_id = base::UnguessableToken::Create();
@@ -1600,8 +1569,7 @@
 
 TEST(V8ScriptValueSerializerForModulesTest,
      TransferClonedMediaStreamTrackFails) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform;
   ScriptState* script_state = scope.GetScriptState();
@@ -1637,8 +1605,7 @@
 
 TEST(V8ScriptValueSerializerForModulesTest,
      TransferDeviceCaptureMediaStreamTrackFails) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform;
 
@@ -1687,8 +1654,7 @@
 
 TEST(V8ScriptValueSerializerForModulesTest,
      TransferScreenCaptureMediaStreamTrackFails) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform;
 
@@ -1741,8 +1707,7 @@
 
 TEST(V8ScriptValueSerializerForModulesTest,
      TransferWindowCaptureMediaStreamTrackFails) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform;
 
@@ -1795,8 +1760,7 @@
 
 TEST(V8ScriptValueSerializerForModulesTest,
      TransferClosedMediaStreamTrackFails) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform;
   ScriptState* script_state = scope.GetScriptState();
@@ -1828,8 +1792,7 @@
 
 TEST(V8ScriptValueSerializerForModulesTest,
      TransferMediaStreamTrackInvalidContentHintFails) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform;
   ScriptState* script_state = scope.GetScriptState();
@@ -1862,8 +1825,7 @@
 
 TEST(V8ScriptValueSerializerForModulesTest,
      TransferMediaStreamTrackNoSessionIdThrows) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform;
   ScriptState* script_state = scope.GetScriptState();
@@ -1916,8 +1878,7 @@
 
 #if !BUILDFLAG(IS_ANDROID)  // SubCaptureTargets are not exposed on Android.
 TEST(V8ScriptValueSerializerForModulesTest, RoundTripCropTarget) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
 
   const String crop_id("8e7e0c22-67a0-4c39-b4dc-a20433262f8e");
@@ -1934,8 +1895,7 @@
 }
 
 TEST(V8ScriptValueSerializerForModulesTest, RoundTripRestrictionTarget) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   ScopedElementCaptureForTest element_capture(true);
 
@@ -1957,8 +1917,7 @@
 
 TEST(V8ScriptValueSerializerForModulesTest,
      ArrayBufferDetachKeyPreventsTransfer) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   ScriptState* script_state = scope.GetScriptState();
   v8::Isolate* isolate = scope.GetIsolate();
@@ -1992,8 +1951,7 @@
 
 TEST(V8ScriptValueSerializerForModulesTest,
      ArrayBufferDetachKeyDoesNotPreventSerialize) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   ScriptState* script_state = scope.GetScriptState();
   v8::Isolate* isolate = scope.GetIsolate();
diff --git a/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules_test.cc b/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules_test.cc
index d9717cd9..6d549af 100644
--- a/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules_test.cc
+++ b/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules_test.cc
@@ -380,8 +380,7 @@
 }
 
 TEST(IDBKeyFromValue, DeepArray) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   auto key = ScriptToKey(scope,
                          "(() => {"
diff --git a/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base.cc.tmpl b/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base.cc.tmpl
index cf7fa12..a368747 100644
--- a/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base.cc.tmpl
+++ b/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base.cc.tmpl
@@ -1,5 +1,5 @@
 {% from 'templates/macros.tmpl' import license, print_if, source_files_for_generated_file %}
-{% from 'templates/fields/field.tmpl' import encode, const_ref, getter_expression, getter_method_name, setter_expression, fieldwise_debug_diff, fieldwise_diff, group_source_expression, field_source_expression %}
+{% from 'templates/fields/field.tmpl' import encode, const_ref, getter_expression, getter_method_name, setter_expression, fieldwise_debug_diff, fieldwise_diff, group_source_expression, field_source_expression, group_getter_expression %}
 {% from 'templates/fields/group.tmpl' import define_field_group_class %}
 {% import 'templates/fields/derived_flag.tmpl' as derived_flag %}
 {{license()}}
@@ -51,6 +51,26 @@
     {% endfor %}
   }
 
+{% macro find_changed_groups(group) -%}
+  {% if group_getter_expression(group) != '' %}
+  if (!base::ValuesEquivalent({{group_getter_expression(group)}},
+      other_style.{{group_getter_expression(group)}})) {
+    output.emplace_back("{{group_getter_expression(group)}}",
+        sizeof(*{{group_getter_expression(group)}}));
+  }
+  {% endif %}
+  {% for subgroup in group.subgroups -%}
+    {{find_changed_groups(subgroup)}}
+  {%- endfor %}
+{%- endmacro %}
+
+Vector<std::pair<String, size_t>>
+ComputedStyleBase::FindChangedGroups(const ComputedStyleBase &other_style) const {
+  Vector<std::pair<String, size_t>> output;
+  {{ find_changed_groups(computed_style) }}
+  return output;
+}
+
 void ComputedStyleBase::Trace(Visitor* visitor) const {
   static_cast<const ComputedStyle*>(this)->TraceAfterDispatch(visitor);
 }
diff --git a/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base.h.tmpl b/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base.h.tmpl
index 46bf126..cf26c1ed 100644
--- a/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base.h.tmpl
+++ b/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base.h.tmpl
@@ -200,6 +200,20 @@
   CORE_EXPORT Vector<DebugDiff> DebugDiffFields(const ComputedStyleBase& o) const;
 #endif // DCHECK_IS_ON()
 
+  // Find a list of which subgroups listed have changed between this and the
+  // other ComputedStyle(Base); output a list of the changed groups and their
+  // sizes in bytes. This is meant for more precise memory tracking than just
+  // looking at the Oilpan statistics, or for finding out (empirically)
+  // which groups are affected by setting a specific property. It is used
+  // only in the style perftest, not in the normal rendering engine.
+  //
+  // Note that if you change something deep in a subgroup like e.g. a->b->c,
+  // both a->b and a will also be recorded, as they must be modified to get
+  // the pointer in place. The fixed 4- or 8-byte Oilpan header overhead
+  // is not included.
+  Vector<std::pair<String, size_t>>
+  FindChangedGroups(const ComputedStyleBase &other_style) const;
+
   CORE_EXPORT void Trace(Visitor* visitor) const;
   void TraceAfterDispatch(Visitor* visitor) const {
     {% for subgroup in computed_style.subgroups %}
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index 459c8fe..f086a093 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1501,6 +1501,7 @@
   sources += rebase_path(blink_core_tests_intersection_observer,
                          "",
                          "intersection_observer")
+  sources += rebase_path(blink_core_tests_layout, "", "layout")
   sources += rebase_path(blink_core_tests_lcp_critical_path_predictor,
                          "",
                          "lcp_critical_path_predictor")
diff --git a/third_party/blink/renderer/core/accessibility/ax_object_cache.h b/third_party/blink/renderer/core/accessibility/ax_object_cache.h
index cd6d39c7..a7a55df 100644
--- a/third_party/blink/renderer/core/accessibility/ax_object_cache.h
+++ b/third_party/blink/renderer/core/accessibility/ax_object_cache.h
@@ -55,7 +55,6 @@
 class HTMLOptionElement;
 class HTMLFrameOwnerElement;
 class HTMLSelectElement;
-class LocalFrameView;
 struct PhysicalRect;
 
 class CORE_EXPORT AXObjectCache : public GarbageCollected<AXObjectCache> {
@@ -174,7 +173,6 @@
   virtual void InlineTextBoxesUpdated(LayoutObject*) = 0;
 
   // Called when the scroll offset changes.
-  virtual void HandleScrollPositionChanged(LocalFrameView*) = 0;
   virtual void HandleScrollPositionChanged(LayoutObject*) = 0;
 
   virtual void HandleScrolledToAnchor(const Node* anchor_node) = 0;
diff --git a/third_party/blink/renderer/core/clipboard/data_transfer.cc b/third_party/blink/renderer/core/clipboard/data_transfer.cc
index 36af37b..f4302575 100644
--- a/third_party/blink/renderer/core/clipboard/data_transfer.cc
+++ b/third_party/blink/renderer/core/clipboard/data_transfer.cc
@@ -413,7 +413,7 @@
 
   // Rasterize upfront, since DragImage::create() is going to do it anyway
   // (SkImage::asLegacyBitmap).
-  SkSurfaceProps surface_props(0, kUnknown_SkPixelGeometry);
+  SkSurfaceProps surface_props;
   sk_sp<SkSurface> surface = SkSurfaces::Raster(
       SkImageInfo::MakeN32Premul(device_size.width(), device_size.height()),
       &surface_props);
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.cc b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
index 2b83c0f..dd50368 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
@@ -2512,6 +2512,11 @@
     }
   };
 
+  const ComputedStyle* old_style = nullptr;
+  if (count_computed_style_bytes_) {
+    old_style = state.StyleBuilder().CloneStyle();
+  }
+
   // In order to use-count whether or not legacy overlapping properties
   // made a real difference to the ComputedStyle, we first apply the cascade
   // while filtering out such properties. If the filter did reject
@@ -2527,6 +2532,17 @@
                               state.StyleBuilder());
   }
 
+  if (count_computed_style_bytes_) {
+    constexpr size_t kOilpanOverheadBytes =
+        sizeof(void*);  // See cppgc::internal::HeapObjectHeader.
+    const ComputedStyle* new_style = state.StyleBuilder().CloneStyle();
+    for (const auto& [group_name, size] :
+         old_style->FindChangedGroups(*new_style)) {
+      computed_style_bytes_used_ += size + kOilpanOverheadBytes;
+    }
+    computed_style_bytes_used_ += sizeof(*new_style) + kOilpanOverheadBytes;
+  }
+
   // NOTE: This flag (and the length conversion flags) need to be set before the
   // entry is added to the matched properties cache, or it will be wrong on
   // cache hits.
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.h b/third_party/blink/renderer/core/css/resolver/style_resolver.h
index 0c2beac..e262d5f 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver.h
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver.h
@@ -232,6 +232,22 @@
   // propagation of BODY style to HTML and viewport.
   bool ShouldStopBodyPropagation(const Element& body_or_html);
 
+  // If enabled, will attempt to count the number of bytes used by the
+  // generated ComputedStyle objects. Note that most of the fast paths
+  // (e.g. inline incremental style) and the non-element styles
+  // (e.g. @page) are not accounted for. However, the effect of the MPC
+  // should be correctly modeled. Note that there is a significant
+  // CPU overhead through this, and it will also allocate a fairly large
+  // amount of temporary GC memory for the diffing.
+  void SetCountComputedStyleBytes(bool enabled) {
+    count_computed_style_bytes_ = enabled;
+    computed_style_bytes_used_ = 0;
+  }
+  size_t GetComputedStyleBytesUsed() const {
+    DCHECK(count_computed_style_bytes_);
+    return computed_style_bytes_used_;
+  }
+
   void Trace(Visitor*) const;
 
  private:
@@ -360,6 +376,10 @@
   // style computations; see `EnsureElementForFormattedText`.
   Member<Element> formatted_text_element_;
 
+  // See SetCountComputedStyleBytes().
+  bool count_computed_style_bytes_ = false;
+  size_t computed_style_bytes_used_ = 0;
+
   bool print_media_type_ = false;
   bool was_viewport_resized_ = false;
 
diff --git a/third_party/blink/renderer/core/css/style_perftest.cc b/third_party/blink/renderer/core/css/style_perftest.cc
index dcf79e9..203bcb2 100644
--- a/third_party/blink/renderer/core/css/style_perftest.cc
+++ b/third_party/blink/renderer/core/css/style_perftest.cc
@@ -9,6 +9,7 @@
 // not yet checked in. The tests will be skipped if you don't have the
 // files available.
 
+#include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
 #include "third_party/blink/renderer/core/css/style_recalc_change.h"
 
 #include "base/command_line.h"
@@ -138,6 +139,12 @@
   base::TimeDelta recalc_style_time;
   int64_t gc_allocated_bytes;
   int64_t partition_allocated_bytes;  // May be negative due to bugs.
+
+  // Part of gc_allocated_bytes, but much more precise. Only enabled if
+  // --measure-computed-style-memory is set -- and if so, gc_allocated_bytes
+  // is going to be much higher due to the extra allocated objects used for
+  // diffing.
+  int64_t computed_style_used_bytes;
 };
 
 static StylePerfResult MeasureStyleForDumpedPage(
@@ -154,6 +161,10 @@
   int recalc_iterations =
       recalc_iterations_str.empty() ? 1 : stoi(recalc_iterations_str);
 
+  const bool measure_computed_style_memory =
+      base::CommandLine::ForCurrentProcess()->HasSwitch(
+          "measure-computed-style-memory");
+
   // Do a forced GC run before we start loading anything, so that we have
   // a more stable baseline. Note that even with this, the GC deltas tend to
   // be different depending on what other tests that run before, so if you want
@@ -184,6 +195,11 @@
     page = LoadDumpedPage(json->GetDict(), result.parse_time, reporter);
   }
 
+  page->GetDocument()
+      .GetStyleEngine()
+      .GetStyleResolver()
+      .SetCountComputedStyleBytes(measure_computed_style_memory);
+
   if (!parse_only) {
     {
       base::ElapsedTimer style_timer;
@@ -219,6 +235,12 @@
   result.gc_allocated_bytes = gc_allocated_bytes - orig_gc_allocated_bytes;
   result.partition_allocated_bytes =
       partition_allocated_bytes - orig_partition_allocated_bytes;
+  if (measure_computed_style_memory) {
+    result.computed_style_used_bytes = page->GetDocument()
+                                           .GetStyleEngine()
+                                           .GetStyleResolver()
+                                           .GetComputedStyleBytesUsed();
+  }
 
   return result;
 }
@@ -246,9 +268,19 @@
     reporter.AddResult("RecalcTime", result.recalc_style_time);
   }
 
-  reporter.RegisterImportantMetric("GCAllocated", "kB");
-  reporter.AddResult("GCAllocated",
-                     static_cast<size_t>(result.gc_allocated_bytes) / 1024);
+  if (result.computed_style_used_bytes > 0) {
+    reporter.RegisterImportantMetric("ComputedStyleUsed", "kB");
+    reporter.AddResult(
+        "ComputedStyleUsed",
+        static_cast<size_t>(result.computed_style_used_bytes) / 1024);
+
+    // Don't print GCAllocated if we measured ComputedStyle; it causes
+    // much more GC churn, which will skew the metrics.
+  } else {
+    reporter.RegisterImportantMetric("GCAllocated", "kB");
+    reporter.AddResult("GCAllocated",
+                       static_cast<size_t>(result.gc_allocated_bytes) / 1024);
+  }
 
   reporter.RegisterImportantMetric("PartitionAllocated", "kB");
   reporter.AddResult(
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index 8fb7962e..1bc79254 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -1918,6 +1918,14 @@
     return render_blocking_resource_manager_.Get();
   }
 
+  void SetHasRenderBlockingExpectLinkElements(bool flag) {
+    has_render_blocking_expect_link_elements_ = flag;
+  }
+
+  bool HasRenderBlockingExpectLinkElements() const {
+    return has_render_blocking_expect_link_elements_;
+  }
+
   // Called when a previously render-blocking resource is no longer render-
   // blocking, due to it has finished loading or has given up render-blocking.
   void RenderBlockingResourceUnblocked();
@@ -2427,6 +2435,8 @@
   bool have_explicitly_disabled_dns_prefetch_;
   bool contains_plugins_;
 
+  bool has_render_blocking_expect_link_elements_ = false;
+
   // Set to true whenever shadow root is attached to document. Does not
   // get reset if all roots are removed.
   bool may_contain_shadow_roots_ = false;
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 7941bd9..9ef5d2db 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -2464,9 +2464,12 @@
       GetDocument().GetStyleEngine().IdChangedForElement(old_id, new_id, *this);
     }
 
-    if (auto* manager = GetDocument().GetRenderBlockingResourceManager();
-        manager && IsFinishedParsingChildren()) {
-      manager->RemovePendingParsingElement(new_id);
+    if (GetDocument().HasRenderBlockingExpectLinkElements() &&
+        IsFinishedParsingChildren()) {
+      DCHECK(GetDocument().GetRenderBlockingResourceManager());
+      GetDocument()
+          .GetRenderBlockingResourceManager()
+          ->RemovePendingParsingElement(GetIdAttribute());
     }
   } else if (name == html_names::kClassAttr) {
     if (params.old_value == params.new_value &&
@@ -5418,10 +5421,12 @@
   CheckForSiblingStyleChanges(kFinishedParsingChildren, nullptr, lastChild(),
                               nullptr);
 
-  if (auto* manager = GetDocument().GetRenderBlockingResourceManager()) {
-    manager->RemovePendingParsingElement(GetIdAttribute());
+  if (GetDocument().HasRenderBlockingExpectLinkElements()) {
+    DCHECK(GetDocument().GetRenderBlockingResourceManager());
+    GetDocument()
+        .GetRenderBlockingResourceManager()
+        ->RemovePendingParsingElement(GetIdAttribute());
   }
-
   GetDocument()
       .GetStyleEngine()
       .ScheduleInvalidationsForHasPseudoAffectedByInsertion(
diff --git a/third_party/blink/renderer/core/editing/caret_display_item_client.cc b/third_party/blink/renderer/core/editing/caret_display_item_client.cc
index 9c093074..0d21b70 100644
--- a/third_party/blink/renderer/core/editing/caret_display_item_client.cc
+++ b/third_party/blink/renderer/core/editing/caret_display_item_client.cc
@@ -126,8 +126,8 @@
     // get from CaretLayoutBlock, except for atomic inline-level LayoutBlocks
     // (i.e. display: inline-block). In those cases, the layout object should be
     // either the caret rect's layout block, or its containing block.
-    if (!caret_rect.layout_object->IsLayoutBlock() &&
-        !caret_rect.layout_object->IsAtomicInlineLevel()) {
+    if (!(caret_rect.layout_object->IsLayoutBlock() &&
+          caret_rect.layout_object->IsAtomicInlineLevel())) {
       DCHECK_EQ(caret_block, CaretLayoutBlock(caret_position.AnchorNode(),
                                               caret_rect.layout_object));
     } else if (caret_block != caret_rect.layout_object) {
diff --git a/third_party/blink/renderer/core/events/web_input_event_conversion_test.cc b/third_party/blink/renderer/core/events/web_input_event_conversion_test.cc
index dbe2cc2..9b4b1f6 100644
--- a/third_party/blink/renderer/core/events/web_input_event_conversion_test.cc
+++ b/third_party/blink/renderer/core/events/web_input_event_conversion_test.cc
@@ -83,8 +83,7 @@
 
 class WebInputEventConversionTest : public testing::Test {
  private:
-  test::TaskEnvironment task_environment_{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
 };
 
 TEST_F(WebInputEventConversionTest, WebKeyboardEventBuilder) {
diff --git a/third_party/blink/renderer/core/html/parser/html_document_parser.cc b/third_party/blink/renderer/core/html/parser/html_document_parser.cc
index 8423d60..d851151 100644
--- a/third_party/blink/renderer/core/html/parser/html_document_parser.cc
+++ b/third_party/blink/renderer/core/html/parser/html_document_parser.cc
@@ -29,7 +29,6 @@
 #include <utility>
 
 #include "base/feature_list.h"
-#include "base/memory/scoped_refptr.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/strcat.h"
@@ -67,7 +66,6 @@
 #include "third_party/blink/renderer/core/probe/core_probes.h"
 #include "third_party/blink/renderer/core/script/html_parser_script_runner.h"
 #include "third_party/blink/renderer/platform/bindings/runtime_call_stats.h"
-#include "third_party/blink/renderer/platform/heap/cross_thread_handle.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
@@ -80,7 +78,6 @@
 #include "third_party/blink/renderer/platform/wtf/cross_thread_copier_base.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
 #include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
-#include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h"
 #include "third_party/blink/renderer/platform/wtf/wtf.h"
 
 namespace blink {
@@ -334,37 +331,6 @@
       preload_processing_mode_(GetPreloadProcessingMode()),
       budget_(budget) {}
 
-// Wrap pending preloads in a thread safe and ref-counted object since the
-// vector is added to from a background thread and taken from from the main
-// thread.
-class HTMLDocumentParser::PendingPreloads
-    : public ThreadSafeRefCounted<PendingPreloads> {
- public:
-  PendingPreloads() = default;
-
-  std::unique_ptr<PendingPreloadData> TakeFirst() {
-    base::AutoLock auto_lock(lock_);
-    return preloads_.empty() ? nullptr : preloads_.TakeFirst();
-  }
-
-  // Returns the number of items pending preload after `preload_data` has been
-  // added.
-  size_t Add(std::unique_ptr<PendingPreloadData> preload_data) {
-    base::AutoLock auto_lock(lock_);
-    preloads_.push_back(std::move(preload_data));
-    return preloads_.size();
-  }
-
-  bool IsEmpty() {
-    base::AutoLock auto_lock(lock_);
-    return preloads_.empty();
-  }
-
- private:
-  base::Lock lock_;
-  Deque<std::unique_ptr<PendingPreloadData>> preloads_ GUARDED_BY(lock_);
-};
-
 HTMLDocumentParser::HTMLDocumentParser(HTMLDocument& document,
                                        ParserSynchronizationPolicy sync_policy,
                                        ParserPrefetchPolicy prefetch_policy)
@@ -428,7 +394,6 @@
            document.Url().IsLocalFile())
               ? kInfiniteTokenizationBudget
               : kDefaultMaxTokenizationBudget)),
-      pending_preloads_(base::MakeRefCounted<PendingPreloads>()),
       scheduler_(sync_policy == kAllowDeferredParsing
                      ? Thread::Current()->Scheduler()
                      : nullptr) {
@@ -1536,7 +1501,7 @@
           this, options_, GetPreloadScannerThread()->GetTaskRunner(),
           CrossThreadBindRepeating(
               &HTMLDocumentParser::AddPreloadDataOnBackgroundThread,
-              MakeCrossThreadWeakHandle(this), this->pending_preloads_,
+              WrapCrossThreadWeakPersistent(this),
               GetDocument()->GetTaskRunner(TaskType::kInternalLoading)));
 
       background_scan_fn_ = CrossThreadBindRepeating(
@@ -1573,29 +1538,31 @@
 
 // static
 void HTMLDocumentParser::AddPreloadDataOnBackgroundThread(
-    CrossThreadWeakHandle<HTMLDocumentParser> parser_handle,
-    scoped_refptr<PendingPreloads> pending_preloads,
+    CrossThreadWeakPersistent<HTMLDocumentParser> weak_parser,
     scoped_refptr<base::SequencedTaskRunner> task_runner,
     std::unique_ptr<PendingPreloadData> preload_data) {
   DCHECK(!IsMainThread());
+  auto parser = weak_parser.Lock();
+  if (!parser)
+    return;
 
-  size_t num_pending_preloads = pending_preloads->Add(std::move(preload_data));
+  bool should_post_task = false;
+  {
+    base::AutoLock lock(parser->pending_preload_lock_);
+    // Only post a task if the preload data is empty. Otherwise, a task has
+    // already been posted and will consume the new data.
+    should_post_task = parser->pending_preload_data_.empty();
+    parser->pending_preload_data_.push_back(std::move(preload_data));
+  }
 
-  // Only post a task if the preload data was empty before we added this data.
-  // Otherwise, a task has already been posted and will consume the new data.
-  if (num_pending_preloads == 1) {
+  if (should_post_task) {
     PostCrossThreadTask(
         *task_runner, FROM_HERE,
-        CrossThreadBindOnce(
-            &HTMLDocumentParser::FlushPendingPreloads,
-            MakeUnwrappingCrossThreadWeakHandle(std::move(parser_handle))));
+        CrossThreadBindOnce(&HTMLDocumentParser::FlushPendingPreloads,
+                            std::move(parser)));
   }
 }
 
-bool HTMLDocumentParser::HasPendingPreloads() {
-  return pending_preloads_->IsEmpty();
-}
-
 void HTMLDocumentParser::FlushPendingPreloads() {
   DCHECK(IsMainThread());
   if (!ThreadedPreloadScannerEnabled())
@@ -1605,9 +1572,15 @@
     return;
 
   // Do this in a loop in case more preloads are added in the background.
-  std::unique_ptr<PendingPreloadData> preload_data;
-  while ((preload_data = pending_preloads_->TakeFirst())) {
-    ProcessPreloadData(std::move(preload_data));
+  while (HasPendingPreloads()) {
+    Vector<std::unique_ptr<PendingPreloadData>> preload_data;
+    {
+      base::AutoLock lock(pending_preload_lock_);
+      preload_data = std::move(pending_preload_data_);
+    }
+
+    for (auto& preload : preload_data)
+      ProcessPreloadData(std::move(preload));
   }
 }
 
diff --git a/third_party/blink/renderer/core/html/parser/html_document_parser.h b/third_party/blink/renderer/core/html/parser/html_document_parser.h
index ee22777..c196588 100644
--- a/third_party/blink/renderer/core/html/parser/html_document_parser.h
+++ b/third_party/blink/renderer/core/html/parser/html_document_parser.h
@@ -50,7 +50,6 @@
 #include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h"
 #include "third_party/blink/renderer/core/page/viewport_description.h"
 #include "third_party/blink/renderer/core/script/html_parser_script_runner_host.h"
-#include "third_party/blink/renderer/platform/heap/cross_thread_handle.h"
 #include "third_party/blink/renderer/platform/heap/prefinalizer.h"
 #include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
 #include "third_party/blink/renderer/platform/wtf/deque.h"
@@ -141,14 +140,13 @@
   void ForcePlaintextForTextDocument();
 
  private:
-  enum NextTokenStatus { kNoTokens, kHaveTokens, kHaveTokensAfterScript };
-  class PendingPreloads;
-
   HTMLDocumentParser(Document&,
                      ParserContentPolicy,
                      ParserSynchronizationPolicy,
                      ParserPrefetchPolicy);
 
+  enum NextTokenStatus { kNoTokens, kHaveTokens, kHaveTokensAfterScript };
+
   // DocumentParser
   void Detach() final;
   bool HasInsertionPoint() final;
@@ -236,12 +234,14 @@
 
   // Called on the background thread by |background_scanner_|.
   static void AddPreloadDataOnBackgroundThread(
-      CrossThreadWeakHandle<HTMLDocumentParser> parser_handle,
-      scoped_refptr<PendingPreloads> pending_preloads,
+      CrossThreadWeakPersistent<HTMLDocumentParser> weak_parser,
       scoped_refptr<base::SequencedTaskRunner> task_runner,
       std::unique_ptr<PendingPreloadData> preload_data);
 
-  bool HasPendingPreloads();
+  bool HasPendingPreloads() {
+    base::AutoLock lock(pending_preload_lock_);
+    return !pending_preload_data_.empty();
+  }
 
   // Returns true if the data should be processed (tokenizer pumped) now. If
   // this returns false, SchedulePumpTokenizer() should be called. This is
@@ -285,10 +285,12 @@
   // A timer for how long we are inactive after yielding
   std::unique_ptr<base::ElapsedTimer> yield_timer_;
 
-  // If ThreadedPreloadScanner is enabled, preload data will be added to
-  // `pending_preloads_` from a background thread. The main thread will
-  // take this preload data and send out the requests.
-  scoped_refptr<PendingPreloads> pending_preloads_;
+  // If ThreadedPreloadScanner is enabled, preload data will be added to this
+  // vector from a background thread. The main thread will take this preload
+  // data and send out the requests.
+  base::Lock pending_preload_lock_;
+  Vector<std::unique_ptr<PendingPreloadData>> pending_preload_data_
+      GUARDED_BY(pending_preload_lock_);
 
   ThreadScheduler* scheduler_;
 
diff --git a/third_party/blink/renderer/core/html/parser/html_tree_builder.cc b/third_party/blink/renderer/core/html/parser/html_tree_builder.cc
index 8ed112ae..209239b 100644
--- a/third_party/blink/renderer/core/html/parser/html_tree_builder.cc
+++ b/third_party/blink/renderer/core/html/parser/html_tree_builder.cc
@@ -974,10 +974,13 @@
       ParseError(token);
       break;
     case HTMLTag::kPermission:
-      tree_.ReconstructTheActiveFormattingElements();
-      tree_.InsertSelfClosingHTMLElementDestroyingToken(token);
-      frameset_ok_ = false;
-      break;
+      if (RuntimeEnabledFeatures::PermissionElementEnabled()) {
+        tree_.ReconstructTheActiveFormattingElements();
+        tree_.InsertSelfClosingHTMLElementDestroyingToken(token);
+        frameset_ok_ = false;
+        break;
+      }
+      [[fallthrough]];
     default:
       if (token->GetName() == mathml_names::kMathTag.LocalName()) {
         tree_.ReconstructTheActiveFormattingElements();
diff --git a/third_party/blink/renderer/core/layout/constraint_space_builder_test.cc b/third_party/blink/renderer/core/layout/constraint_space_builder_test.cc
index fc94aa9..99259ea6 100644
--- a/third_party/blink/renderer/core/layout/constraint_space_builder_test.cc
+++ b/third_party/blink/renderer/core/layout/constraint_space_builder_test.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/core/layout/constraint_space_builder.h"
 
 #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
 
 namespace blink {
 namespace {
@@ -14,6 +15,7 @@
 // Asserts that indefinite inline length becomes initial containing
 // block width for horizontal-tb inside vertical document.
 TEST(ConstraintSpaceBuilderTest, AvailableSizeFromHorizontalICB) {
+  test::TaskEnvironment task_environment;
   PhysicalSize icb_size{kIndefiniteSize, LayoutUnit(51)};
 
   ConstraintSpaceBuilder horizontal_builder(
@@ -45,6 +47,7 @@
 // Asserts that indefinite inline length becomes initial containing
 // block height for vertical-lr inside horizontal document.
 TEST(ConstraintSpaceBuilderTest, AvailableSizeFromVerticalICB) {
+  test::TaskEnvironment task_environment;
   PhysicalSize icb_size{LayoutUnit(51), kIndefiniteSize};
 
   ConstraintSpaceBuilder horizontal_builder(
diff --git a/third_party/blink/renderer/core/layout/custom/layout_custom.h b/third_party/blink/renderer/core/layout/custom/layout_custom.h
index 8c00173..9db7bf9e 100644
--- a/third_party/blink/renderer/core/layout/custom/layout_custom.h
+++ b/third_party/blink/renderer/core/layout/custom/layout_custom.h
@@ -50,9 +50,9 @@
   }
 
  private:
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsLayoutCustom() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectCustom || LayoutNGBlockFlow::IsOfType(type);
+    return true;
   }
 
   State state_;
diff --git a/third_party/blink/renderer/core/layout/custom/layout_worklet_test.cc b/third_party/blink/renderer/core/layout/custom/layout_worklet_test.cc
index ecba873..31c4658b 100644
--- a/third_party/blink/renderer/core/layout/custom/layout_worklet_test.cc
+++ b/third_party/blink/renderer/core/layout/custom/layout_worklet_test.cc
@@ -32,6 +32,7 @@
   }
 
   void TearDown() override {
+    Terminate();
     PageTestBase::TearDown();
     ModuleTestBase::TearDown();
   }
diff --git a/third_party/blink/renderer/core/layout/exclusions/exclusion_space_test.cc b/third_party/blink/renderer/core/layout/exclusions/exclusion_space_test.cc
index de527cf3..96871f5 100644
--- a/third_party/blink/renderer/core/layout/exclusions/exclusion_space_test.cc
+++ b/third_party/blink/renderer/core/layout/exclusions/exclusion_space_test.cc
@@ -6,6 +6,7 @@
 
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
 
 namespace blink {
 
@@ -82,6 +83,7 @@
 // Tests that an empty exclusion space returns exactly one layout opportunity
 // each one, and sized appropriately given the area.
 TEST(ExclusionSpaceTest, Empty) {
+  test::TaskEnvironment task_environment;
   ExclusionSpace exclusion_space;
 
   LayoutOpportunityVector opportunites = exclusion_space.AllLayoutOpportunities(
@@ -111,6 +113,7 @@
 }
 
 TEST(ExclusionSpaceTest, SingleExclusion) {
+  test::TaskEnvironment task_environment;
   ExclusionSpace exclusion_space;
 
   exclusion_space.Add(
@@ -173,6 +176,7 @@
 }
 
 TEST(ExclusionSpaceTest, TwoExclusions) {
+  test::TaskEnvironment task_environment;
   ExclusionSpace exclusion_space;
 
   exclusion_space.Add(
@@ -213,6 +217,7 @@
 //      |xxx|   +---+
 // 40   +---+
 TEST(ExclusionSpaceTest, SolidEdges) {
+  test::TaskEnvironment task_environment;
   ExclusionSpace exclusion_space;
 
   exclusion_space.Add(
@@ -264,6 +269,7 @@
 // 30               |NEW|
 //                  +---+
 TEST(ExclusionSpaceTest, OverlappingWithShelf) {
+  test::TaskEnvironment task_environment;
   ExclusionSpace exclusion_space;
 
   exclusion_space.Add(
@@ -311,6 +317,7 @@
 // 30              |xxx|
 //    X----------------X
 TEST(ExclusionSpaceTest, InsertBetweenShelves) {
+  test::TaskEnvironment task_environment;
   ExclusionSpace exclusion_space;
 
   exclusion_space.Add(
@@ -345,6 +352,7 @@
 }
 
 TEST(ExclusionSpaceTest, InitialLetterBasic) {
+  test::TaskEnvironment task_environment;
   constexpr LayoutUnit kAvailableInlineSize = LayoutUnit(300);
   ExclusionSpaceForTesting exclusion_space(kAvailableInlineSize);
 
@@ -387,6 +395,7 @@
 }
 
 TEST(ExclusionSpaceTest, InitialLetterDirectionRight) {
+  test::TaskEnvironment task_environment;
   constexpr LayoutUnit kAvailableInlineSize = LayoutUnit(300);
   ExclusionSpaceForTesting exclusion_space(kAvailableInlineSize);
 
@@ -442,6 +451,7 @@
 }
 
 TEST(ExclusionSpaceTest, InitialLetterFloatLeft1) {
+  test::TaskEnvironment task_environment;
   constexpr LayoutUnit kAvailableInlineSize = LayoutUnit(300);
   ExclusionSpaceForTesting exclusion_space(kAvailableInlineSize);
 
@@ -494,6 +504,7 @@
 }
 
 TEST(ExclusionSpaceTest, InitialLetterFloatLeft2) {
+  test::TaskEnvironment task_environment;
   constexpr LayoutUnit kAvailableInlineSize = LayoutUnit(300);
   ExclusionSpaceForTesting exclusion_space(kAvailableInlineSize);
 
@@ -548,6 +559,7 @@
 }
 
 TEST(ExclusionSpaceTest, InitialLetterFloatLeft2ClearLeft) {
+  test::TaskEnvironment task_environment;
   constexpr LayoutUnit kAvailableInlineSize = LayoutUnit(300);
   ExclusionSpaceForTesting exclusion_space(kAvailableInlineSize);
 
@@ -604,6 +616,7 @@
 }
 
 TEST(ExclusionSpaceTest, InitialLetterFloatLeftAndRight) {
+  test::TaskEnvironment task_environment;
   constexpr LayoutUnit kAvailableInlineSize = LayoutUnit(300);
   ExclusionSpaceForTesting exclusion_space(kAvailableInlineSize);
 
@@ -669,6 +682,7 @@
 }
 
 TEST(ExclusionSpaceTest, InitialLetterFloatLeftAfterBreak) {
+  test::TaskEnvironment task_environment;
   constexpr LayoutUnit kAvailableInlineSize = LayoutUnit(300);
   ExclusionSpaceForTesting exclusion_space(kAvailableInlineSize);
 
@@ -726,6 +740,7 @@
 }
 
 TEST(ExclusionSpaceTest, InitialLetterFloatRight2) {
+  test::TaskEnvironment task_environment;
   constexpr LayoutUnit kAvailableInlineSize = LayoutUnit(300);
   ExclusionSpaceForTesting exclusion_space(kAvailableInlineSize);
 
@@ -786,6 +801,7 @@
 }
 
 TEST(ExclusionSpaceTest, ZeroInlineSizeOpportunity) {
+  test::TaskEnvironment task_environment;
   ExclusionSpace exclusion_space;
 
   exclusion_space.Add(
@@ -805,6 +821,7 @@
 }
 
 TEST(ExclusionSpaceTest, NegativeInlineSizeOpportunityLeft) {
+  test::TaskEnvironment task_environment;
   ExclusionSpace exclusion_space;
 
   exclusion_space.Add(
@@ -824,6 +841,7 @@
 }
 
 TEST(ExclusionSpaceTest, NegativeInlineSizeOpportunityRight) {
+  test::TaskEnvironment task_environment;
   ExclusionSpace exclusion_space;
 
   exclusion_space.Add(
@@ -843,6 +861,7 @@
 }
 
 TEST(ExclusionSpaceTest, PreInitialization) {
+  test::TaskEnvironment task_environment;
   ExclusionSpace original_exclusion_space;
 
   original_exclusion_space.Add(
@@ -897,6 +916,7 @@
 }
 
 TEST(ExclusionSpaceTest, MergeExclusionSpacesNoPreviousExclusions) {
+  test::TaskEnvironment task_environment;
   ExclusionSpace old_input;
   ExclusionSpace old_output = old_input;
 
@@ -924,6 +944,7 @@
 }
 
 TEST(ExclusionSpaceTest, MergeExclusionSpacesPreviousExclusions) {
+  test::TaskEnvironment task_environment;
   ExclusionSpace old_input;
   old_input.Add(
       ExclusionArea::Create(BfcRect(BfcOffset(LayoutUnit(20), LayoutUnit(45)),
@@ -963,6 +984,7 @@
 }
 
 TEST(ExclusionSpaceTest, MergeExclusionSpacesNoOutputExclusions) {
+  test::TaskEnvironment task_environment;
   ExclusionSpace old_input;
   old_input.Add(
       ExclusionArea::Create(BfcRect(BfcOffset(LayoutUnit(20), LayoutUnit(45)),
diff --git a/third_party/blink/renderer/core/layout/flex/layout_flexible_box.h b/third_party/blink/renderer/core/layout/flex/layout_flexible_box.h
index 7079aee..9ecb5c5 100644
--- a/third_party/blink/renderer/core/layout/flex/layout_flexible_box.h
+++ b/third_party/blink/renderer/core/layout/flex/layout_flexible_box.h
@@ -43,9 +43,9 @@
                       const ComputedStyle& style) const override;
   void RemoveChild(LayoutObject*) override;
 
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsFlexibleBox() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectFlexibleBox || LayoutBlock::IsOfType(type);
+    return true;
   }
 };
 
diff --git a/third_party/blink/renderer/core/layout/forms/layout_button.h b/third_party/blink/renderer/core/layout/forms/layout_button.h
index 2824bff..00e3c9e5 100644
--- a/third_party/blink/renderer/core/layout/forms/layout_button.h
+++ b/third_party/blink/renderer/core/layout/forms/layout_button.h
@@ -33,9 +33,9 @@
       const LayoutObject* child,
       ComputedStyleBuilder& child_style_builder) const override;
 
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsButton() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectButton || LayoutFlexibleBox::IsOfType(type);
+    return true;
   }
 
   Member<LayoutBlock> inner_;
diff --git a/third_party/blink/renderer/core/layout/forms/layout_fieldset.cc b/third_party/blink/renderer/core/layout/forms/layout_fieldset.cc
index 41dd7c6..f7369574 100644
--- a/third_party/blink/renderer/core/layout/forms/layout_fieldset.cc
+++ b/third_party/blink/renderer/core/layout/forms/layout_fieldset.cc
@@ -171,10 +171,6 @@
   child_style_builder.SetScrollStartY(StyleRef().ScrollStartY());
 }
 
-bool LayoutFieldset::IsOfType(LayoutObjectType type) const {
-  return type == kLayoutObjectFieldset || LayoutNGBlockFlow::IsOfType(type);
-}
-
 void LayoutFieldset::InvalidatePaint(
     const PaintInvalidatorContext& context) const {
   // Fieldset's box decoration painting depends on the legend geometry.
diff --git a/third_party/blink/renderer/core/layout/forms/layout_fieldset.h b/third_party/blink/renderer/core/layout/forms/layout_fieldset.h
index 841762e..84631fa 100644
--- a/third_party/blink/renderer/core/layout/forms/layout_fieldset.h
+++ b/third_party/blink/renderer/core/layout/forms/layout_fieldset.h
@@ -36,7 +36,10 @@
   }
 
  protected:
-  bool IsOfType(LayoutObjectType) const override;
+  bool IsFieldset() const final {
+    NOT_DESTROYED();
+    return true;
+  }
   void InsertedIntoTree() override;
   void UpdateAnonymousChildStyle(
       const LayoutObject* child,
diff --git a/third_party/blink/renderer/core/layout/forms/layout_text_control_multi_line.cc b/third_party/blink/renderer/core/layout/forms/layout_text_control_multi_line.cc
index 690b95c..f742a62 100644
--- a/third_party/blink/renderer/core/layout/forms/layout_text_control_multi_line.cc
+++ b/third_party/blink/renderer/core/layout/forms/layout_text_control_multi_line.cc
@@ -16,11 +16,6 @@
   return To<TextControlElement>(GetNode())->InnerEditorElement();
 }
 
-bool LayoutTextControlMultiLine::IsOfType(LayoutObjectType type) const {
-  return type == kLayoutObjectTextControlMultiLine ||
-         LayoutNGBlockFlow::IsOfType(type);
-}
-
 void LayoutTextControlMultiLine::StyleDidChange(
     StyleDifference style_diff,
     const ComputedStyle* old_style) {
diff --git a/third_party/blink/renderer/core/layout/forms/layout_text_control_multi_line.h b/third_party/blink/renderer/core/layout/forms/layout_text_control_multi_line.h
index b3538c6..d948b27 100644
--- a/third_party/blink/renderer/core/layout/forms/layout_text_control_multi_line.h
+++ b/third_party/blink/renderer/core/layout/forms/layout_text_control_multi_line.h
@@ -17,7 +17,10 @@
  private:
   HTMLElement* InnerEditorElement() const;
 
-  bool IsOfType(LayoutObjectType) const override;
+  bool IsTextArea() const final {
+    NOT_DESTROYED();
+    return true;
+  }
 
   const char* GetName() const override {
     NOT_DESTROYED();
diff --git a/third_party/blink/renderer/core/layout/forms/layout_text_control_single_line.cc b/third_party/blink/renderer/core/layout/forms/layout_text_control_single_line.cc
index de578a6..48571cd 100644
--- a/third_party/blink/renderer/core/layout/forms/layout_text_control_single_line.cc
+++ b/third_party/blink/renderer/core/layout/forms/layout_text_control_single_line.cc
@@ -24,11 +24,6 @@
       shadow_element_names::kIdTextFieldContainer);
 }
 
-bool LayoutTextControlSingleLine::IsOfType(LayoutObjectType type) const {
-  return type == kLayoutObjectTextControlSingleLine ||
-         LayoutNGBlockFlow::IsOfType(type);
-}
-
 void LayoutTextControlSingleLine::StyleDidChange(
     StyleDifference style_diff,
     const ComputedStyle* old_style) {
diff --git a/third_party/blink/renderer/core/layout/forms/layout_text_control_single_line.h b/third_party/blink/renderer/core/layout/forms/layout_text_control_single_line.h
index cf0c848..afdd53b 100644
--- a/third_party/blink/renderer/core/layout/forms/layout_text_control_single_line.h
+++ b/third_party/blink/renderer/core/layout/forms/layout_text_control_single_line.h
@@ -18,7 +18,10 @@
   HTMLElement* InnerEditorElement() const;
   Element* ContainerElement() const;
 
-  bool IsOfType(LayoutObjectType) const override;
+  bool IsTextField() const final {
+    NOT_DESTROYED();
+    return true;
+  }
 
   const char* GetName() const override {
     NOT_DESTROYED();
diff --git a/third_party/blink/renderer/core/layout/geometry/axis_test.cc b/third_party/blink/renderer/core/layout/geometry/axis_test.cc
index e11f52d..00f76597f 100644
--- a/third_party/blink/renderer/core/layout/geometry/axis_test.cc
+++ b/third_party/blink/renderer/core/layout/geometry/axis_test.cc
@@ -5,10 +5,12 @@
 #include "third_party/blink/renderer/core/layout/geometry/axis.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
 
 namespace blink {
 
 TEST(AxisTest, LogicalAxesOperators) {
+  test::TaskEnvironment task_environment;
   // operator |
   EXPECT_EQ(kLogicalAxisNone, (kLogicalAxisNone | kLogicalAxisNone));
   EXPECT_EQ(kLogicalAxisInline, (kLogicalAxisNone | kLogicalAxisInline));
@@ -42,6 +44,7 @@
 }
 
 TEST(AxisTest, PhysicalAxesOperators) {
+  test::TaskEnvironment task_environment;
   // operator |
   EXPECT_EQ(kPhysicalAxisNone, (kPhysicalAxisNone | kPhysicalAxisNone));
   EXPECT_EQ(kPhysicalAxisHorizontal,
@@ -80,6 +83,7 @@
 }
 
 TEST(AxisTest, ToPhysicalAxes) {
+  test::TaskEnvironment task_environment;
   ASSERT_TRUE(IsHorizontalWritingMode(WritingMode::kHorizontalTb));
   ASSERT_FALSE(IsHorizontalWritingMode(WritingMode::kVerticalRl));
 
@@ -105,6 +109,7 @@
 }
 
 TEST(AxisTest, ToLogicalAxes) {
+  test::TaskEnvironment task_environment;
   ASSERT_TRUE(IsHorizontalWritingMode(WritingMode::kHorizontalTb));
   ASSERT_FALSE(IsHorizontalWritingMode(WritingMode::kVerticalRl));
 
diff --git a/third_party/blink/renderer/core/layout/geometry/box_strut_test.cc b/third_party/blink/renderer/core/layout/geometry/box_strut_test.cc
index e8b37b51..b40c604 100644
--- a/third_party/blink/renderer/core/layout/geometry/box_strut_test.cc
+++ b/third_party/blink/renderer/core/layout/geometry/box_strut_test.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/core/layout/geometry/box_strut.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
 
 namespace blink {
 
@@ -13,6 +14,7 @@
 // Ideally, this would be tested by BoxStrut::ConvertToPhysical, but
 // this has not been implemented yet.
 TEST(GeometryUnitsTest, ConvertPhysicalStrutToLogical) {
+  test::TaskEnvironment task_environment;
   LayoutUnit left{5}, right{10}, top{15}, bottom{20};
   PhysicalBoxStrut physical{top, right, bottom, left};
 
@@ -48,6 +50,7 @@
 }
 
 TEST(GeometryUnitsTest, ConvertLogicalStrutToPhysical) {
+  test::TaskEnvironment task_environment;
   LayoutUnit left{5}, right{10}, top{15}, bottom{20};
   BoxStrut logical(left, right, top, bottom);
   BoxStrut converted =
@@ -95,6 +98,7 @@
 }
 
 TEST(PhysicalBoxStrutTest, Constructors) {
+  test::TaskEnvironment task_environment;
   PhysicalBoxStrut result(0, std::numeric_limits<int>::max(), -1,
                           std::numeric_limits<int>::min());
   EXPECT_EQ(LayoutUnit(), result.top);
@@ -105,6 +109,7 @@
 }
 
 TEST(PhysicalBoxStrutTest, Enclosing) {
+  test::TaskEnvironment task_environment;
   ASSERT_LT(0.01f, LayoutUnit::Epsilon());
   auto result = PhysicalBoxStrut::Enclosing(
       gfx::OutsetsF()
@@ -119,6 +124,7 @@
 }
 
 TEST(PhysicalBoxStrutTest, Unite) {
+  test::TaskEnvironment task_environment;
   PhysicalBoxStrut strut(LayoutUnit(10));
   strut.Unite(
       {LayoutUnit(10), LayoutUnit(11), LayoutUnit(0), LayoutUnit::Max()});
diff --git a/third_party/blink/renderer/core/layout/geometry/logical_rect_test.cc b/third_party/blink/renderer/core/layout/geometry/logical_rect_test.cc
index 3ce56560..7e7db26 100644
--- a/third_party/blink/renderer/core/layout/geometry/logical_rect_test.cc
+++ b/third_party/blink/renderer/core/layout/geometry/logical_rect_test.cc
@@ -6,12 +6,14 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
 
 namespace blink {
 
 namespace {
 
 TEST(LogicalRectTest, AddOffset) {
+  test::TaskEnvironment task_environment;
   EXPECT_EQ(LogicalRect(1, 2, 3, 4) + LogicalOffset(5, 6),
             LogicalRect(6, 8, 3, 4));
 }
diff --git a/third_party/blink/renderer/core/layout/geometry/physical_rect_test.cc b/third_party/blink/renderer/core/layout/geometry/physical_rect_test.cc
index 04867b6..650f48e 100644
--- a/third_party/blink/renderer/core/layout/geometry/physical_rect_test.cc
+++ b/third_party/blink/renderer/core/layout/geometry/physical_rect_test.cc
@@ -7,6 +7,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
 #include "third_party/blink/renderer/platform/geometry/infinite_int_rect.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 
 namespace blink {
@@ -14,6 +15,7 @@
 namespace {
 
 TEST(PhysicalRectTest, AddOffset) {
+  test::TaskEnvironment task_environment;
   EXPECT_EQ(PhysicalRect(1, 2, 3, 4) + PhysicalOffset(5, 6),
             PhysicalRect(6, 8, 3, 4));
 }
@@ -74,6 +76,7 @@
 }
 
 TEST(PhysicalRectTest, SquaredDistanceTo) {
+  test::TaskEnvironment task_environment;
   PhysicalRect rect(0, 0, 200, 200);
   EXPECT_EQ(200, rect.SquaredDistanceTo(PhysicalOffset(-10, -10)))
       << "over the top-left corner";
@@ -122,6 +125,7 @@
 }
 
 TEST(PhysicalRectTest, InclusiveIntersect) {
+  test::TaskEnvironment task_environment;
   PhysicalRect rect(11, 12, 0, 0);
   EXPECT_TRUE(rect.InclusiveIntersect(PhysicalRect(11, 12, 13, 14)));
   EXPECT_EQ(rect, PhysicalRect(11, 12, 0, 0));
@@ -140,6 +144,7 @@
 }
 
 TEST(PhysicalRectTest, IntersectsInclusively) {
+  test::TaskEnvironment task_environment;
   PhysicalRect a(11, 12, 0, 0);
   PhysicalRect b(11, 12, 13, 14);
   // An empty rect can have inclusive intersection.
@@ -184,6 +189,7 @@
 }
 
 TEST(PhysicalRectTest, ToEnclosingRect) {
+  test::TaskEnvironment task_environment;
   LayoutUnit small;
   small.SetRawValue(1);
   PhysicalRect small_dimensions_rect(LayoutUnit(42.5f), LayoutUnit(84.5f),
@@ -235,6 +241,7 @@
 }
 
 TEST(LayoutRectTest, EdgesOnPixelBoundaries) {
+  test::TaskEnvironment task_environment;
   EXPECT_TRUE(PhysicalRect().EdgesOnPixelBoundaries());
   EXPECT_TRUE(PhysicalRect(1, 1, 1, 1).EdgesOnPixelBoundaries());
   EXPECT_TRUE(PhysicalRect(1, -1, 1, 1).EdgesOnPixelBoundaries());
@@ -272,6 +279,7 @@
 }
 
 TEST(PhysicalRectTest, ExpandEdgesToPixelBoundaries) {
+  test::TaskEnvironment task_environment;
   LayoutUnit small;
   small.SetRawValue(1);
   PhysicalRect small_dimensions_rect(LayoutUnit(42.5f), LayoutUnit(84.5f),
@@ -325,6 +333,7 @@
 }
 
 TEST(PhysicalRectTest, InfiniteIntRect) {
+  test::TaskEnvironment task_environment;
   gfx::Rect r = InfiniteIntRect();
   EXPECT_TRUE(r.Contains(gfx::Rect(-8000000, -8000000, 16000000, 16000000)));
 
diff --git a/third_party/blink/renderer/core/layout/geometry/physical_size_test.cc b/third_party/blink/renderer/core/layout/geometry/physical_size_test.cc
index 42b4b519..66add42 100644
--- a/third_party/blink/renderer/core/layout/geometry/physical_size_test.cc
+++ b/third_party/blink/renderer/core/layout/geometry/physical_size_test.cc
@@ -6,10 +6,12 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
 
 namespace blink {
 
 TEST(PhysicalSizeTest, MultipleFloat) {
+  test::TaskEnvironment task_environment;
   EXPECT_EQ(PhysicalSize(100, 7), PhysicalSize(200, 14) * 0.5f);
   EXPECT_EQ(PhysicalSize(-100, -7), PhysicalSize(200, 14) * -0.5f);
   EXPECT_EQ(PhysicalSize(0, 0),
@@ -17,16 +19,19 @@
 }
 
 TEST(PhysicalSizeTest, ExpandedTo) {
+  test::TaskEnvironment task_environment;
   EXPECT_EQ(PhysicalSize(13, 7), PhysicalSize(13, 1).ExpandedTo({10, 7}));
   EXPECT_EQ(PhysicalSize(17, 1), PhysicalSize(13, 1).ExpandedTo({17, 1}));
 }
 
 TEST(PhysicalSizeTest, ShrunkTo) {
+  test::TaskEnvironment task_environment;
   EXPECT_EQ(PhysicalSize(10, 1), PhysicalSize(13, 1).ShrunkTo({10, 7}));
   EXPECT_EQ(PhysicalSize(13, -1), PhysicalSize(13, 1).ShrunkTo({14, -1}));
 }
 
 TEST(PhysicalSizeTest, FitToAspectRatioShrink) {
+  test::TaskEnvironment task_environment;
   PhysicalSize aspect_ratio(50000, 40000);
   EXPECT_EQ(PhysicalSize(1250, 1000),
             PhysicalSize(2000, 1000)
@@ -44,6 +49,7 @@
 }
 
 TEST(PhysicalSizeTest, FitToAspectRatioGrow) {
+  test::TaskEnvironment task_environment;
   PhysicalSize aspect_ratio(50000, 40000);
   EXPECT_EQ(PhysicalSize(2000, 1600),
             PhysicalSize(2000, 1000)
diff --git a/third_party/blink/renderer/core/layout/geometry/writing_mode_converter_test.cc b/third_party/blink/renderer/core/layout/geometry/writing_mode_converter_test.cc
index 5574e475..5119424 100644
--- a/third_party/blink/renderer/core/layout/geometry/writing_mode_converter_test.cc
+++ b/third_party/blink/renderer/core/layout/geometry/writing_mode_converter_test.cc
@@ -6,12 +6,14 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
 
 namespace blink {
 
 namespace {
 
 TEST(WritingModeConverterTest, ConvertLogicalOffsetToPhysicalOffset) {
+  test::TaskEnvironment task_environment;
   LogicalOffset logical_offset(20, 30);
   PhysicalSize outer_size(300, 400);
   PhysicalSize inner_size(5, 65);
@@ -69,6 +71,7 @@
 }
 
 TEST(WritingModeConverterTest, ConvertPhysicalOffsetToLogicalOffset) {
+  test::TaskEnvironment task_environment;
   PhysicalOffset physical_offset(20, 30);
   PhysicalSize outer_size(300, 400);
   PhysicalSize inner_size(5, 65);
diff --git a/third_party/blink/renderer/core/layout/grid/layout_grid.h b/third_party/blink/renderer/core/layout/grid/layout_grid.h
index 13dea7e..fa2e835 100644
--- a/third_party/blink/renderer/core/layout/grid/layout_grid.h
+++ b/third_party/blink/renderer/core/layout/grid/layout_grid.h
@@ -43,13 +43,12 @@
 
   const GridLayoutData* LayoutData() const;
 
- protected:
-  bool IsOfType(LayoutObjectType type) const override {
+ private:
+  bool IsLayoutGrid() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectGrid || LayoutBlock::IsOfType(type);
+    return true;
   }
 
- private:
   Vector<LayoutUnit> ComputeTrackSizeRepeaterForRange(
       const GridLayoutTrackCollection& track_collection,
       wtf_size_t range_index) const;
diff --git a/third_party/blink/renderer/core/layout/ink_overflow_test.cc b/third_party/blink/renderer/core/layout/ink_overflow_test.cc
index 37c01c2..46a18bc 100644
--- a/third_party/blink/renderer/core/layout/ink_overflow_test.cc
+++ b/third_party/blink/renderer/core/layout/ink_overflow_test.cc
@@ -7,6 +7,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
 
 namespace blink {
 
@@ -21,7 +22,10 @@
 
 using testing::ElementsAre;
 
-class InkOverflowTest : public testing::Test {};
+class InkOverflowTest : public testing::Test {
+ private:
+  test::TaskEnvironment task_environment_;
+};
 
 TEST_F(InkOverflowTest, Empty) {
   InkOverflow overflow;
diff --git a/third_party/blink/renderer/core/layout/layout_block.cc b/third_party/blink/renderer/core/layout/layout_block.cc
index e5fb06c..1df9b4d 100644
--- a/third_party/blink/renderer/core/layout/layout_block.cc
+++ b/third_party/blink/renderer/core/layout/layout_block.cc
@@ -668,8 +668,8 @@
 // so the firstChild() is nullptr if the only child is an empty inline-block.
 inline bool LayoutBlock::IsInlineBoxWrapperActuallyChild() const {
   NOT_DESTROYED();
-  return IsInlineBlockOrInlineTable() && !Size().IsEmpty() && GetNode() &&
-         EditingIgnoresContent(*GetNode());
+  return IsInline() && IsAtomicInlineLevel() && !Size().IsEmpty() &&
+         GetNode() && EditingIgnoresContent(*GetNode());
 }
 
 PhysicalRect LayoutBlock::LocalCaretRect(
diff --git a/third_party/blink/renderer/core/layout/layout_block.h b/third_party/blink/renderer/core/layout/layout_block.h
index 11cb37d..ae9d9a9 100644
--- a/third_party/blink/renderer/core/layout/layout_block.h
+++ b/third_party/blink/renderer/core/layout/layout_block.h
@@ -235,15 +235,6 @@
                        const PhysicalOffset& additional_offset,
                        OutlineType) const override;
 
-  // TODO(jchaffraix): We should rename this function as inline-flex and
-  // inline-grid as also covered.
-  // Alternatively it should be removed as we clarify the meaning of
-  // IsAtomicInlineLevel to imply isInline.
-  bool IsInlineBlockOrInlineTable() const final {
-    NOT_DESTROYED();
-    return IsInline() && IsAtomicInlineLevel();
-  }
-
   bool IsInSelfHitTestingPhase(HitTestPhase phase) const final {
     NOT_DESTROYED();
     return phase == HitTestPhase::kSelfBlockBackground;
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index 45c37d76..36260f4 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -466,7 +466,6 @@
 LayoutBox::LayoutBox(ContainerNode* node)
     : LayoutBoxModelObject(node),
       intrinsic_logical_widths_initial_block_size_(LayoutUnit::Min()) {
-  SetIsBox();
   if (blink::IsA<HTMLLegendElement>(node))
     SetIsHTMLLegendElement();
 }
diff --git a/third_party/blink/renderer/core/layout/layout_box.h b/third_party/blink/renderer/core/layout/layout_box.h
index ad9b1467..90d2d8a 100644
--- a/third_party/blink/renderer/core/layout/layout_box.h
+++ b/third_party/blink/renderer/core/layout/layout_box.h
@@ -1408,8 +1408,10 @@
     return *rare_data_.Get();
   }
 
-  bool IsBox() const =
-      delete;  // This will catch anyone doing an unnecessary check.
+  bool IsBox() const final {
+    NOT_DESTROYED();
+    return true;
+  }
 
   void LocationChanged();
 
diff --git a/third_party/blink/renderer/core/layout/layout_br.h b/third_party/blink/renderer/core/layout/layout_br.h
index 3b18e0068..80cf239 100644
--- a/third_party/blink/renderer/core/layout/layout_br.h
+++ b/third_party/blink/renderer/core/layout/layout_br.h
@@ -43,9 +43,9 @@
   // to return a rect that includes space to illustrate a newline.
   using LayoutText::LocalSelectionVisualRect;
 
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsBR() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectBr || LayoutText::IsOfType(type);
+    return true;
   }
 
   int CaretMinOffset() const override;
diff --git a/third_party/blink/renderer/core/layout/layout_counter.h b/third_party/blink/renderer/core/layout/layout_counter.h
index 555443b..551210ea 100644
--- a/third_party/blink/renderer/core/layout/layout_counter.h
+++ b/third_party/blink/renderer/core/layout/layout_counter.h
@@ -108,9 +108,9 @@
   void WillBeDestroyed() override;
 
  private:
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsCounter() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectCounter || LayoutText::IsOfType(type);
+    return true;
   }
   String OriginalText() const override;
 
diff --git a/third_party/blink/renderer/core/layout/layout_custom_scrollbar_part.h b/third_party/blink/renderer/core/layout/layout_custom_scrollbar_part.h
index f3284bf4..29457a0 100644
--- a/third_party/blink/renderer/core/layout/layout_custom_scrollbar_part.h
+++ b/third_party/blink/renderer/core/layout/layout_custom_scrollbar_part.h
@@ -82,10 +82,9 @@
   LayoutUnit MarginLeft() const override;
   LayoutUnit MarginRight() const override;
 
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsLayoutCustomScrollbarPart() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectCustomScrollbarPart ||
-           LayoutReplaced::IsOfType(type);
+    return true;
   }
   ScrollableArea* GetScrollableArea() const {
     NOT_DESTROYED();
diff --git a/third_party/blink/renderer/core/layout/layout_embedded_object.h b/third_party/blink/renderer/core/layout/layout_embedded_object.h
index aaff035..4fb2d622 100644
--- a/third_party/blink/renderer/core/layout/layout_embedded_object.h
+++ b/third_party/blink/renderer/core/layout/layout_embedded_object.h
@@ -60,10 +60,9 @@
   void UpdateLayout() final;
   void UpdateAfterLayout() final;
 
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsEmbeddedObject() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectEmbeddedObject ||
-           LayoutEmbeddedContent::IsOfType(type);
+    return true;
   }
   void ComputeIntrinsicSizingInfo(IntrinsicSizingInfo&) const override;
 
diff --git a/third_party/blink/renderer/core/layout/layout_frame.h b/third_party/blink/renderer/core/layout/layout_frame.h
index 8b82096e..6d007a02 100644
--- a/third_party/blink/renderer/core/layout/layout_frame.h
+++ b/third_party/blink/renderer/core/layout/layout_frame.h
@@ -41,9 +41,9 @@
   }
 
  private:
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsFrame() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectFrame || LayoutEmbeddedContent::IsOfType(type);
+    return true;
   }
 };
 
diff --git a/third_party/blink/renderer/core/layout/layout_frame_set.cc b/third_party/blink/renderer/core/layout/layout_frame_set.cc
index e3bda82..5ad59b93 100644
--- a/third_party/blink/renderer/core/layout/layout_frame_set.cc
+++ b/third_party/blink/renderer/core/layout/layout_frame_set.cc
@@ -19,11 +19,6 @@
   return "LayoutFrameSet";
 }
 
-bool LayoutFrameSet::IsOfType(LayoutObjectType type) const {
-  NOT_DESTROYED();
-  return type == kLayoutObjectFrameSet || LayoutBlock::IsOfType(type);
-}
-
 bool LayoutFrameSet::IsChildAllowed(LayoutObject* child,
                                     const ComputedStyle&) const {
   NOT_DESTROYED();
diff --git a/third_party/blink/renderer/core/layout/layout_frame_set.h b/third_party/blink/renderer/core/layout/layout_frame_set.h
index 55f0b90..2d3139bc 100644
--- a/third_party/blink/renderer/core/layout/layout_frame_set.h
+++ b/third_party/blink/renderer/core/layout/layout_frame_set.h
@@ -15,7 +15,10 @@
 
  private:
   const char* GetName() const override;
-  bool IsOfType(LayoutObjectType type) const override;
+  bool IsFrameSet() const final {
+    NOT_DESTROYED();
+    return true;
+  }
   bool IsChildAllowed(LayoutObject* child, const ComputedStyle&) const override;
   void AddChild(LayoutObject* new_child, LayoutObject* before_child) override;
   void RemoveChild(LayoutObject* child) override;
diff --git a/third_party/blink/renderer/core/layout/layout_html_canvas.h b/third_party/blink/renderer/core/layout/layout_html_canvas.h
index 7696086d..7b04b6f3 100644
--- a/third_party/blink/renderer/core/layout/layout_html_canvas.h
+++ b/third_party/blink/renderer/core/layout/layout_html_canvas.h
@@ -37,9 +37,9 @@
  public:
   explicit LayoutHTMLCanvas(HTMLCanvasElement*);
 
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsCanvas() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectCanvas || LayoutReplaced::IsOfType(type);
+    return true;
   }
 
   void InvalidatePaint(const PaintInvalidatorContext&) const final;
diff --git a/third_party/blink/renderer/core/layout/layout_iframe.cc b/third_party/blink/renderer/core/layout/layout_iframe.cc
index 16b2d72..8920234c 100644
--- a/third_party/blink/renderer/core/layout/layout_iframe.cc
+++ b/third_party/blink/renderer/core/layout/layout_iframe.cc
@@ -32,11 +32,6 @@
 LayoutIFrame::LayoutIFrame(HTMLFrameOwnerElement* element)
     : LayoutEmbeddedContent(element) {}
 
-bool LayoutIFrame::IsInlineBlockOrInlineTable() const {
-  NOT_DESTROYED();
-  return IsInline();
-}
-
 void LayoutIFrame::UpdateLayout() {
   NOT_DESTROYED();
   DCHECK(NeedsLayout());
diff --git a/third_party/blink/renderer/core/layout/layout_iframe.h b/third_party/blink/renderer/core/layout/layout_iframe.h
index 4814ff27..0d75d48 100644
--- a/third_party/blink/renderer/core/layout/layout_iframe.h
+++ b/third_party/blink/renderer/core/layout/layout_iframe.h
@@ -41,13 +41,11 @@
   }
 
  private:
-  bool IsInlineBlockOrInlineTable() const override;
-
   void UpdateLayout() override;
 
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsLayoutIFrame() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectIFrame || LayoutEmbeddedContent::IsOfType(type);
+    return true;
   }
 };
 
diff --git a/third_party/blink/renderer/core/layout/layout_image.h b/third_party/blink/renderer/core/layout/layout_image.h
index 35212ae5..c114f01 100644
--- a/third_party/blink/renderer/core/layout/layout_image.h
+++ b/third_party/blink/renderer/core/layout/layout_image.h
@@ -130,9 +130,9 @@
 
   void Paint(const PaintInfo&) const final;
 
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsLayoutImage() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectImage || LayoutReplaced::IsOfType(type);
+    return true;
   }
 
   void WillBeDestroyed() override;
diff --git a/third_party/blink/renderer/core/layout/layout_media.h b/third_party/blink/renderer/core/layout/layout_media.h
index 924014c1..27cd4a4 100644
--- a/third_party/blink/renderer/core/layout/layout_media.h
+++ b/third_party/blink/renderer/core/layout/layout_media.h
@@ -73,9 +73,9 @@
   LayoutUnit ComputePanelWidth(const PhysicalRect& media_width) const;
 
  protected:
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsMedia() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectMedia || LayoutImage::IsOfType(type);
+    return true;
   }
 
  private:
diff --git a/third_party/blink/renderer/core/layout/layout_multi_column_set.h b/third_party/blink/renderer/core/layout/layout_multi_column_set.h
index a2c3751..e12e100 100644
--- a/third_party/blink/renderer/core/layout/layout_multi_column_set.h
+++ b/third_party/blink/renderer/core/layout/layout_multi_column_set.h
@@ -106,10 +106,9 @@
     return fragmentainer_groups_;
   }
 
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsLayoutMultiColumnSet() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectMultiColumnSet ||
-           LayoutBlockFlow::IsOfType(type);
+    return true;
   }
   bool CanHaveChildren() const final {
     NOT_DESTROYED();
diff --git a/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h b/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h
index 12b4f48..59d9307 100644
--- a/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h
+++ b/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h
@@ -18,10 +18,9 @@
 // multicol container.
 class LayoutMultiColumnSpannerPlaceholder final : public LayoutBox {
  public:
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsLayoutMultiColumnSpannerPlaceholder() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectMultiColumnSpannerPlaceholder ||
-           LayoutBox::IsOfType(type);
+    return true;
   }
 
   static LayoutMultiColumnSpannerPlaceholder* CreateAnonymous(
diff --git a/third_party/blink/renderer/core/layout/layout_ng_block_flow.cc b/third_party/blink/renderer/core/layout/layout_ng_block_flow.cc
index 3d14430..c274349 100644
--- a/third_party/blink/renderer/core/layout/layout_ng_block_flow.cc
+++ b/third_party/blink/renderer/core/layout/layout_ng_block_flow.cc
@@ -22,11 +22,6 @@
   LayoutBlockFlow::Trace(visitor);
 }
 
-bool LayoutNGBlockFlow::IsOfType(LayoutObjectType type) const {
-  NOT_DESTROYED();
-  return type == kLayoutObjectNGBlockFlow || LayoutBlockFlow::IsOfType(type);
-}
-
 void LayoutNGBlockFlow::StyleDidChange(StyleDifference diff,
                                        const ComputedStyle* old_style) {
   NOT_DESTROYED();
diff --git a/third_party/blink/renderer/core/layout/layout_ng_block_flow.h b/third_party/blink/renderer/core/layout/layout_ng_block_flow.h
index c2e29dc..7beb311 100644
--- a/third_party/blink/renderer/core/layout/layout_ng_block_flow.h
+++ b/third_party/blink/renderer/core/layout/layout_ng_block_flow.h
@@ -38,7 +38,10 @@
   void ClearInlineNodeData() final;
 
  protected:
-  bool IsOfType(LayoutObjectType) const override;
+  bool IsLayoutNGBlockFlow() const final {
+    NOT_DESTROYED();
+    return true;
+  }
   void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
 
   void AddOutlineRects(OutlineRectCollector&,
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h
index c83e810..a0fc4b7 100644
--- a/third_party/blink/renderer/core/layout/layout_object.h
+++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -856,207 +856,202 @@
     NOT_DESTROYED();
     return false;
   }
-  bool IsBR() const {
+  virtual bool IsBox() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectBr);
+    return false;
   }
-  bool IsCanvas() const {
+  virtual bool IsText() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectCanvas);
+    return false;
   }
-  bool IsCounter() const {
+  virtual bool IsBR() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectCounter);
+    return false;
   }
-  bool IsEmbeddedObject() const {
+  virtual bool IsCanvas() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectEmbeddedObject);
+    return false;
   }
-  bool IsFieldset() const {
+  virtual bool IsCounter() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectFieldset);
+    return false;
   }
-  bool IsFrame() const {
+  virtual bool IsEmbeddedObject() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectFrame);
+    return false;
   }
-  bool IsFrameSet() const {
+  virtual bool IsFieldset() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectFrameSet);
+    return false;
   }
-  bool IsLayoutNGBlockFlow() const {
+  virtual bool IsFrame() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectNGBlockFlow);
+    return false;
   }
-  bool IsFlexibleBox() const {
+  virtual bool IsFrameSet() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectFlexibleBox);
+    return false;
   }
-  bool IsLayoutListItem() const {
+  virtual bool IsLayoutNGBlockFlow() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectListItem);
+    return false;
   }
-  bool IsInlineListItem() const {
+  virtual bool IsFlexibleBox() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectInlineListItem);
+    return false;
   }
-  bool IsLayoutInsideListMarker() const {
+  virtual bool IsLayoutListItem() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectInsideListMarker);
+    return false;
   }
-  bool IsLayoutOutsideListMarker() const {
+  virtual bool IsInlineListItem() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectOutsideListMarker);
+    return false;
   }
-  bool IsLayoutTextCombine() const {
+  virtual bool IsLayoutInsideListMarker() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectTextCombine);
+    return false;
   }
-  bool IsLayoutTableCol() const {
+  virtual bool IsLayoutOutsideListMarker() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectTableCol);
+    return false;
   }
-  bool IsListMarkerImage() const {
+  virtual bool IsLayoutTextCombine() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectListMarkerImage);
+    return false;
   }
-  bool IsMathML() const {
+  virtual bool IsLayoutTableCol() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectMathML);
+    return false;
   }
-  bool IsMathMLRoot() const {
+  virtual bool IsListMarkerImage() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectMathMLRoot);
+    return false;
   }
-  bool IsMedia() const {
+  virtual bool IsMathML() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectMedia);
+    return false;
   }
-  bool IsProgress() const {
+  virtual bool IsMathMLRoot() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectProgress);
+    return false;
   }
-  bool IsQuote() const {
+  virtual bool IsMedia() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectQuote);
+    return false;
   }
-  bool IsButton() const {
+  virtual bool IsProgress() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectButton);
+    return false;
   }
-  bool IsLayoutCustom() const {
+  virtual bool IsQuote() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectCustom);
+    return false;
   }
-  bool IsLayoutGrid() const {
+  virtual bool IsButton() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectGrid);
+    return false;
   }
-  bool IsLayoutIFrame() const {
+  virtual bool IsLayoutCustom() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectIFrame);
+    return false;
   }
-  bool IsLayoutImage() const {
+  virtual bool IsLayoutGrid() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectImage);
+    return false;
   }
-  bool IsLayoutMultiColumnSet() const {
+  virtual bool IsLayoutIFrame() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectMultiColumnSet);
+    return false;
   }
-  bool IsLayoutMultiColumnSpannerPlaceholder() const {
+  virtual bool IsLayoutImage() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectMultiColumnSpannerPlaceholder);
+    return false;
   }
-  bool IsLayoutReplaced() const {
+  virtual bool IsLayoutMultiColumnSet() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectReplaced);
+    return false;
   }
-  bool IsLayoutCustomScrollbarPart() const {
+  virtual bool IsLayoutMultiColumnSpannerPlaceholder() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectCustomScrollbarPart);
+    return false;
   }
-  bool IsLayoutView() const {
+  virtual bool IsLayoutReplaced() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectView);
+    return false;
   }
-  bool IsRuby() const {
+  virtual bool IsLayoutCustomScrollbarPart() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectRuby);
+    return false;
   }
-  bool IsRubyBase() const {
+  virtual bool IsLayoutView() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectRubyBase);
+    return false;
   }
-  bool IsRubyColumn() const {
+  virtual bool IsRuby() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectRubyColumn);
+    return false;
   }
-  bool IsRubyText() const {
+  virtual bool IsRubyBase() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectRubyText);
+    return false;
   }
-  bool IsTable() const {
+  virtual bool IsRubyColumn() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectTable);
+    return false;
   }
-  bool IsTableCaption() const {
+  virtual bool IsRubyText() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectTableCaption);
+    return false;
   }
-  bool IsTableCell() const {
+  virtual bool IsTable() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectTableCell);
+    return false;
   }
-  bool IsTableRow() const {
+  virtual bool IsTableCaption() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectTableRow);
+    return false;
   }
-  bool IsTableSection() const {
+  virtual bool IsTableCell() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectTableSection);
+    return false;
   }
-  bool IsTextArea() const {
+  virtual bool IsTableRow() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectTextControlMultiLine);
+    return false;
   }
-  bool IsTextControl() const {
+  virtual bool IsTableSection() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectTextControlMultiLine) ||
-           IsOfType(kLayoutObjectTextControlSingleLine);
+    return false;
   }
-  bool IsTextField() const {
+  virtual bool IsTextArea() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectTextControlSingleLine);
+    return false;
   }
-  bool IsVideo() const {
+  virtual bool IsTextField() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectVideo);
+    return false;
   }
-  bool IsWidget() const {
+  virtual bool IsVideo() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectWidget);
+    return false;
   }
-
+  virtual bool IsWidget() const {
+    NOT_DESTROYED();
+    return false;
+  }
   virtual bool IsImage() const {
     NOT_DESTROYED();
     return false;
   }
-
   virtual bool IsViewTransitionContent() const {
     NOT_DESTROYED();
     return false;
   }
-
   virtual bool IsViewTransitionRoot() const {
     NOT_DESTROYED();
     return false;
   }
-
-  virtual bool IsInlineBlockOrInlineTable() const {
-    NOT_DESTROYED();
-    return false;
-  }
   virtual bool IsLayoutBlock() const {
     NOT_DESTROYED();
     return false;
@@ -1082,6 +1077,11 @@
     return false;
   }
 
+  bool IsTextControl() const {
+    NOT_DESTROYED();
+    return IsTextArea() || IsTextField();
+  }
+
   bool IsDocumentElement() const {
     NOT_DESTROYED();
     return GetDocument().documentElement() == node_;
@@ -1209,73 +1209,73 @@
   // FIXME: Until all SVG layoutObjects can be subclasses of
   // LayoutSVGModelObject we have to add SVG layoutObject methods to
   // LayoutObject with an NOTREACHED() default implementation.
-  bool IsSVG() const {
+  virtual bool IsSVG() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectSVG);
+    return false;
   }
-  bool IsSVGRoot() const {
+  virtual bool IsSVGRoot() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectSVGRoot);
+    return false;
   }
   bool IsSVGChild() const {
     NOT_DESTROYED();
     return IsSVG() && !IsSVGRoot();
   }
-  bool IsSVGContainer() const {
+  virtual bool IsSVGContainer() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectSVGContainer);
+    return false;
   }
-  bool IsSVGTransformableContainer() const {
+  virtual bool IsSVGTransformableContainer() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectSVGTransformableContainer);
+    return false;
   }
-  bool IsSVGViewportContainer() const {
+  virtual bool IsSVGViewportContainer() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectSVGViewportContainer);
+    return false;
   }
-  bool IsSVGHiddenContainer() const {
+  virtual bool IsSVGHiddenContainer() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectSVGHiddenContainer);
+    return false;
   }
-  bool IsSVGShape() const {
+  virtual bool IsSVGShape() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectSVGShape);
+    return false;
   }
-  bool IsSVGTextPath() const {
+  virtual bool IsSVGTextPath() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectSVGTextPath);
+    return false;
   }
-  bool IsSVGTSpan() const {
+  virtual bool IsSVGTSpan() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectSVGTSpan);
+    return false;
   }
-  bool IsSVGInline() const {
+  virtual bool IsSVGInline() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectSVGInline);
+    return false;
   }
-  bool IsSVGInlineText() const {
+  virtual bool IsSVGInlineText() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectSVGInlineText);
+    return false;
   }
-  bool IsSVGImage() const {
+  virtual bool IsSVGImage() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectSVGImage);
+    return false;
   }
-  bool IsSVGForeignObject() const {
+  virtual bool IsSVGForeignObject() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectSVGForeignObject);
+    return false;
   }
-  bool IsSVGResourceContainer() const {
+  virtual bool IsSVGResourceContainer() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectSVGResourceContainer);
+    return false;
   }
-  bool IsSVGFilterPrimitive() const {
+  virtual bool IsSVGFilterPrimitive() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectSVGFilterPrimitive);
+    return false;
   }
-  bool IsSVGText() const {
+  virtual bool IsSVGText() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectSVGText);
+    return false;
   }
 
   // FIXME: Those belong into a SVG specific base-class for all layoutObjects
@@ -1416,15 +1416,6 @@
     NOT_DESTROYED();
     return positioned_state_ != kIsStaticallyPositioned;
   }
-
-  bool IsText() const {
-    NOT_DESTROYED();
-    return bitfields_.IsText();
-  }
-  bool IsBox() const {
-    NOT_DESTROYED();
-    return bitfields_.IsBox();
-  }
   bool IsInline() const {
     NOT_DESTROYED();
     return bitfields_.IsInline();
@@ -2075,14 +2066,6 @@
 
   void SetHasBoxDecorationBackground(bool);
 
-  void SetIsText() {
-    NOT_DESTROYED();
-    bitfields_.SetIsText(true);
-  }
-  void SetIsBox() {
-    NOT_DESTROYED();
-    bitfields_.SetIsBox(true);
-  }
   void SetIsAtomicInlineLevel(bool is_atomic_inline_level) {
     NOT_DESTROYED();
     bitfields_.SetIsAtomicInlineLevel(is_atomic_inline_level);
@@ -3463,76 +3446,6 @@
   bool BelongsToElementChangingOverflowBehaviour() const;
 
  protected:
-  // Identifiers for each of LayoutObject subclasses.
-  // The identifier name for blink::LayoutFoo should be kLayoutObjectFoo.
-  enum LayoutObjectType {
-    kLayoutObjectBr,
-    kLayoutObjectButton,
-    kLayoutObjectCanvas,
-    kLayoutObjectCounter,
-    kLayoutObjectCustom,
-    kLayoutObjectCustomScrollbarPart,
-    kLayoutObjectEmbeddedObject,
-    kLayoutObjectFieldset,
-    kLayoutObjectFlexibleBox,
-    kLayoutObjectFrame,
-    kLayoutObjectFrameSet,
-    kLayoutObjectGrid,
-    kLayoutObjectIFrame,
-    kLayoutObjectImage,
-    kLayoutObjectInlineListItem,
-    kLayoutObjectInsideListMarker,
-    kLayoutObjectListItem,
-    kLayoutObjectListMarkerImage,
-    kLayoutObjectMathML,
-    kLayoutObjectMathMLRoot,
-    kLayoutObjectMedia,
-    kLayoutObjectMultiColumnSet,
-    kLayoutObjectMultiColumnSpannerPlaceholder,
-    kLayoutObjectNGBlockFlow,
-    kLayoutObjectOutsideListMarker,
-    kLayoutObjectProgress,
-    kLayoutObjectQuote,
-    kLayoutObjectReplaced,
-    kLayoutObjectRuby,
-    kLayoutObjectRubyBase,
-    kLayoutObjectRubyColumn,
-    kLayoutObjectRubyText,
-    kLayoutObjectTable,
-    kLayoutObjectTableCaption,
-    kLayoutObjectTableCell,
-    kLayoutObjectTableCol,
-    kLayoutObjectTableRow,
-    kLayoutObjectTableSection,
-    kLayoutObjectTextCombine,
-    kLayoutObjectTextControlMultiLine,
-    kLayoutObjectTextControlSingleLine,
-    kLayoutObjectVideo,
-    kLayoutObjectView,
-    kLayoutObjectWidget,
-
-    kLayoutObjectSVG, /* Keep by itself? */
-    kLayoutObjectSVGContainer,
-    kLayoutObjectSVGFilterPrimitive,
-    kLayoutObjectSVGForeignObject,
-    kLayoutObjectSVGHiddenContainer,
-    kLayoutObjectSVGImage,
-    kLayoutObjectSVGInline,
-    kLayoutObjectSVGInlineText,
-    kLayoutObjectSVGResourceContainer,
-    kLayoutObjectSVGRoot,
-    kLayoutObjectSVGShape,
-    kLayoutObjectSVGTSpan,
-    kLayoutObjectSVGText,
-    kLayoutObjectSVGTextPath,
-    kLayoutObjectSVGTransformableContainer,
-    kLayoutObjectSVGViewportContainer,
-  };
-  virtual bool IsOfType(LayoutObjectType type) const {
-    NOT_DESTROYED();
-    return false;
-  }
-
   void SetDestroyedForTesting() {
     NOT_DESTROYED();
     bitfields_.SetBeingDestroyed(true);
@@ -3858,8 +3771,6 @@
           descendant_needs_paint_property_update_(true),
           floating_(false),
           is_anonymous(!node),
-          is_text_(false),
-          is_box_(false),
           is_inline_(true),
           is_in_layout_ng_inline_formatting_context_(false),
           is_atomic_inline_level_(false),
@@ -4003,8 +3914,6 @@
     ADD_BOOLEAN_BITFIELD(floating_, Floating);
 
     ADD_BOOLEAN_BITFIELD(is_anonymous, IsAnonymous);
-    ADD_BOOLEAN_BITFIELD(is_text_, IsText);
-    ADD_BOOLEAN_BITFIELD(is_box_, IsBox);
 
     // This boolean represents whether the LayoutObject is 'inline-level'
     // (a CSS concept). Inline-level boxes are laid out inside a line. If
diff --git a/third_party/blink/renderer/core/layout/layout_progress.h b/third_party/blink/renderer/core/layout/layout_progress.h
index c312fb9..44fdd7fc 100644
--- a/third_party/blink/renderer/core/layout/layout_progress.h
+++ b/third_party/blink/renderer/core/layout/layout_progress.h
@@ -57,9 +57,9 @@
 
  protected:
   void WillBeDestroyed() override;
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsProgress() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectProgress || LayoutBlockFlow::IsOfType(type);
+    return true;
   }
 
   bool IsAnimating() const;
diff --git a/third_party/blink/renderer/core/layout/layout_quote.h b/third_party/blink/renderer/core/layout/layout_quote.h
index 7f4e621..f4eeca0 100644
--- a/third_party/blink/renderer/core/layout/layout_quote.h
+++ b/third_party/blink/renderer/core/layout/layout_quote.h
@@ -83,9 +83,9 @@
 
  private:
   void WillBeDestroyed() override;
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsQuote() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectQuote || LayoutInline::IsOfType(type);
+    return true;
   }
   void StyleDidChange(StyleDifference, const ComputedStyle*) override;
   void WillBeRemovedFromTree() override;
diff --git a/third_party/blink/renderer/core/layout/layout_replaced.h b/third_party/blink/renderer/core/layout/layout_replaced.h
index 8bcd0522..3d2611d 100644
--- a/third_party/blink/renderer/core/layout/layout_replaced.h
+++ b/third_party/blink/renderer/core/layout/layout_replaced.h
@@ -179,9 +179,9 @@
 
   PositionWithAffinity PositionForPoint(const PhysicalOffset&) const override;
 
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsLayoutReplaced() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectReplaced || LayoutBox::IsOfType(type);
+    return true;
   }
 
   // The intrinsic size for a replaced element is based on its content's natural
diff --git a/third_party/blink/renderer/core/layout/layout_ruby.h b/third_party/blink/renderer/core/layout/layout_ruby.h
index 4a1de7b1..dd7f294 100644
--- a/third_party/blink/renderer/core/layout/layout_ruby.h
+++ b/third_party/blink/renderer/core/layout/layout_ruby.h
@@ -81,9 +81,9 @@
   void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
 
  private:
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsRuby() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectRuby || LayoutInline::IsOfType(type);
+    return true;
   }
 
   Member<RubyContainer> ruby_container_;
diff --git a/third_party/blink/renderer/core/layout/layout_ruby_as_block.cc b/third_party/blink/renderer/core/layout/layout_ruby_as_block.cc
index 365245d..95555bd 100644
--- a/third_party/blink/renderer/core/layout/layout_ruby_as_block.cc
+++ b/third_party/blink/renderer/core/layout/layout_ruby_as_block.cc
@@ -27,11 +27,6 @@
   LayoutNGBlockFlow::Trace(visitor);
 }
 
-bool LayoutRubyAsBlock::IsOfType(LayoutObjectType type) const {
-  NOT_DESTROYED();
-  return type == kLayoutObjectRuby || LayoutNGBlockFlow::IsOfType(type);
-}
-
 void LayoutRubyAsBlock::AddChild(LayoutObject* child,
                                  LayoutObject* before_child) {
   NOT_DESTROYED();
diff --git a/third_party/blink/renderer/core/layout/layout_ruby_as_block.h b/third_party/blink/renderer/core/layout/layout_ruby_as_block.h
index cb536fa..916365806 100644
--- a/third_party/blink/renderer/core/layout/layout_ruby_as_block.h
+++ b/third_party/blink/renderer/core/layout/layout_ruby_as_block.h
@@ -28,7 +28,11 @@
     NOT_DESTROYED();
     return "LayoutRubyAsBlock";
   }
-  bool IsOfType(LayoutObjectType type) const override;
+  bool IsRuby() const final {
+    NOT_DESTROYED();
+    return true;
+  }
+
   void AddChild(LayoutObject* child,
                 LayoutObject* before_child = nullptr) override;
   void RemoveChild(LayoutObject* child) override;
diff --git a/third_party/blink/renderer/core/layout/layout_ruby_base.cc b/third_party/blink/renderer/core/layout/layout_ruby_base.cc
index 79efb88..1c20820 100644
--- a/third_party/blink/renderer/core/layout/layout_ruby_base.cc
+++ b/third_party/blink/renderer/core/layout/layout_ruby_base.cc
@@ -12,11 +12,6 @@
 
 LayoutRubyBase::~LayoutRubyBase() = default;
 
-bool LayoutRubyBase::IsOfType(LayoutObjectType type) const {
-  NOT_DESTROYED();
-  return type == kLayoutObjectRubyBase || LayoutBlockFlow::IsOfType(type);
-}
-
 bool LayoutRubyBase::IsChildAllowed(LayoutObject*, const ComputedStyle&) const {
   NOT_DESTROYED();
   NOTREACHED();  // Because LayoutRubyColumn manages child types.
diff --git a/third_party/blink/renderer/core/layout/layout_ruby_base.h b/third_party/blink/renderer/core/layout/layout_ruby_base.h
index 7b081d6..324439db 100644
--- a/third_party/blink/renderer/core/layout/layout_ruby_base.h
+++ b/third_party/blink/renderer/core/layout/layout_ruby_base.h
@@ -21,7 +21,10 @@
     NOT_DESTROYED();
     return "LayoutRubyBase";
   }
-  bool IsOfType(LayoutObjectType type) const override;
+  bool IsRubyBase() const final {
+    NOT_DESTROYED();
+    return true;
+  }
   bool IsChildAllowed(LayoutObject*, const ComputedStyle&) const override;
 
   // This function removes all children that are before (!) `before_child`
diff --git a/third_party/blink/renderer/core/layout/layout_ruby_column.cc b/third_party/blink/renderer/core/layout/layout_ruby_column.cc
index b64d5745..6db0f41 100644
--- a/third_party/blink/renderer/core/layout/layout_ruby_column.cc
+++ b/third_party/blink/renderer/core/layout/layout_ruby_column.cc
@@ -31,11 +31,6 @@
 
 LayoutRubyColumn::~LayoutRubyColumn() = default;
 
-bool LayoutRubyColumn::IsOfType(LayoutObjectType type) const {
-  NOT_DESTROYED();
-  return type == kLayoutObjectRubyColumn || LayoutBlockFlow::IsOfType(type);
-}
-
 void LayoutRubyColumn::RemoveLeftoverAnonymousBlock(LayoutBlock*) {
   NOT_DESTROYED();
 }
diff --git a/third_party/blink/renderer/core/layout/layout_ruby_column.h b/third_party/blink/renderer/core/layout/layout_ruby_column.h
index ce852d33..9f2d24cd 100644
--- a/third_party/blink/renderer/core/layout/layout_ruby_column.h
+++ b/third_party/blink/renderer/core/layout/layout_ruby_column.h
@@ -42,7 +42,10 @@
   void AddChild(LayoutObject* child,
                 LayoutObject* before_child = nullptr) override;
   void RemoveChild(LayoutObject* child) override;
-  bool IsOfType(LayoutObjectType type) const override;
+  bool IsRubyColumn() const final {
+    NOT_DESTROYED();
+    return true;
+  }
   void RemoveLeftoverAnonymousBlock(LayoutBlock*) override;
   void UpdateAnonymousChildStyle(const LayoutObject* child,
                                  ComputedStyleBuilder& builder) const override;
diff --git a/third_party/blink/renderer/core/layout/layout_ruby_text.cc b/third_party/blink/renderer/core/layout/layout_ruby_text.cc
index f7dfaf7..adb267c 100644
--- a/third_party/blink/renderer/core/layout/layout_ruby_text.cc
+++ b/third_party/blink/renderer/core/layout/layout_ruby_text.cc
@@ -12,11 +12,6 @@
 
 LayoutRubyText::~LayoutRubyText() = default;
 
-bool LayoutRubyText::IsOfType(LayoutObjectType type) const {
-  NOT_DESTROYED();
-  return type == kLayoutObjectRubyText || LayoutNGBlockFlow::IsOfType(type);
-}
-
 bool LayoutRubyText::CreatesNewFormattingContext() const {
   NOT_DESTROYED();
   // Ruby text objects are pushed around after layout, to become flush with
diff --git a/third_party/blink/renderer/core/layout/layout_ruby_text.h b/third_party/blink/renderer/core/layout/layout_ruby_text.h
index 6eb8b597..faef56b 100644
--- a/third_party/blink/renderer/core/layout/layout_ruby_text.h
+++ b/third_party/blink/renderer/core/layout/layout_ruby_text.h
@@ -21,7 +21,10 @@
     NOT_DESTROYED();
     return "LayoutRubyText";
   }
-  bool IsOfType(LayoutObjectType type) const override;
+  bool IsRubyText() const final {
+    NOT_DESTROYED();
+    return true;
+  }
   bool IsChildAllowed(LayoutObject*, const ComputedStyle&) const override;
   void StyleDidChange(StyleDifference diff,
                       const ComputedStyle* old_style) override;
diff --git a/third_party/blink/renderer/core/layout/layout_text.cc b/third_party/blink/renderer/core/layout/layout_text.cc
index 035ce93..2d83804 100644
--- a/third_party/blink/renderer/core/layout/layout_text.cc
+++ b/third_party/blink/renderer/core/layout/layout_text.cc
@@ -160,8 +160,6 @@
   DCHECK(text_);
   DCHECK(!node || !node->IsDocumentNode());
 
-  SetIsText();
-
   if (node)
     GetFrameView()->IncrementVisuallyNonEmptyCharacterCount(text_.length());
 
diff --git a/third_party/blink/renderer/core/layout/layout_text.h b/third_party/blink/renderer/core/layout/layout_text.h
index 10b61819..f8a82e83 100644
--- a/third_party/blink/renderer/core/layout/layout_text.h
+++ b/third_party/blink/renderer/core/layout/layout_text.h
@@ -397,8 +397,10 @@
   void ApplyTextTransform();
   void SecureText(UChar mask);
 
-  // This will catch anyone doing an unnecessary check.
-  bool IsText() const = delete;
+  bool IsText() const final {
+    NOT_DESTROYED();
+    return true;
+  }
 
   PhysicalRect LocalVisualRectIgnoringVisibility() const final;
 
diff --git a/third_party/blink/renderer/core/layout/layout_text_combine.cc b/third_party/blink/renderer/core/layout/layout_text_combine.cc
index f682eb4..45de269 100644
--- a/third_party/blink/renderer/core/layout/layout_text_combine.cc
+++ b/third_party/blink/renderer/core/layout/layout_text_combine.cc
@@ -64,11 +64,6 @@
 #endif
 }
 
-bool LayoutTextCombine::IsOfType(LayoutObjectType type) const {
-  NOT_DESTROYED();
-  return type == kLayoutObjectTextCombine || LayoutNGBlockFlow::IsOfType(type);
-}
-
 float LayoutTextCombine::DesiredWidth() const {
   DCHECK_EQ(StyleRef().GetFont().GetFontDescription().Orientation(),
             FontOrientation::kHorizontal);
diff --git a/third_party/blink/renderer/core/layout/layout_text_combine.h b/third_party/blink/renderer/core/layout/layout_text_combine.h
index a10b560..34e29a9 100644
--- a/third_party/blink/renderer/core/layout/layout_text_combine.h
+++ b/third_party/blink/renderer/core/layout/layout_text_combine.h
@@ -104,7 +104,10 @@
   static bool ShouldBeParentOf(const LayoutObject& layout_object);
 
  private:
-  bool IsOfType(LayoutObjectType) const override;
+  bool IsLayoutTextCombine() const final {
+    NOT_DESTROYED();
+    return true;
+  }
   const char* GetName() const override {
     NOT_DESTROYED();
     return "LayoutTextCombine";
diff --git a/third_party/blink/renderer/core/layout/layout_video.h b/third_party/blink/renderer/core/layout/layout_video.h
index b69147a8..2c973d2 100644
--- a/third_party/blink/renderer/core/layout/layout_video.h
+++ b/third_party/blink/renderer/core/layout/layout_video.h
@@ -74,9 +74,9 @@
 
   void ImageChanged(WrappedImagePtr, CanDeferInvalidation) override;
 
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsVideo() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectVideo || LayoutMedia::IsOfType(type);
+    return true;
   }
 
   void PaintReplaced(const PaintInfo&,
diff --git a/third_party/blink/renderer/core/layout/layout_view.h b/third_party/blink/renderer/core/layout/layout_view.h
index 920090f..d3debc5f 100644
--- a/third_party/blink/renderer/core/layout/layout_view.h
+++ b/third_party/blink/renderer/core/layout/layout_view.h
@@ -89,9 +89,9 @@
     return "LayoutView";
   }
 
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsLayoutView() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectView || LayoutNGBlockFlow::IsOfType(type);
+    return true;
   }
 
   PaintLayerType LayerTypeRequired() const override {
diff --git a/third_party/blink/renderer/core/layout/length_utils_test.cc b/third_party/blink/renderer/core/layout/length_utils_test.cc
index adedac3b..a334a71 100644
--- a/third_party/blink/renderer/core/layout/length_utils_test.cc
+++ b/third_party/blink/renderer/core/layout/length_utils_test.cc
@@ -14,6 +14,7 @@
 #include "third_party/blink/renderer/platform/geometry/calculation_value.h"
 #include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/geometry/length.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
 
 namespace blink {
 namespace {
@@ -88,6 +89,7 @@
   }
 
   Persistent<const ComputedStyle> initial_style_;
+  test::TaskEnvironment task_environment_;
 };
 
 class LengthUtilsTestWithNode : public RenderingTest {
diff --git a/third_party/blink/renderer/core/layout/list/layout_inline_list_item.cc b/third_party/blink/renderer/core/layout/list/layout_inline_list_item.cc
index f6f11e9..afb4539 100644
--- a/third_party/blink/renderer/core/layout/list/layout_inline_list_item.cc
+++ b/third_party/blink/renderer/core/layout/list/layout_inline_list_item.cc
@@ -29,10 +29,6 @@
   return "LayoutInlineListItem";
 }
 
-bool LayoutInlineListItem::IsOfType(LayoutObjectType type) const {
-  return type == kLayoutObjectInlineListItem || LayoutInline::IsOfType(type);
-}
-
 void LayoutInlineListItem::InsertedIntoTree() {
   LayoutInline::InsertedIntoTree();
   ListItemOrdinal::ItemInsertedOrRemoved(this);
diff --git a/third_party/blink/renderer/core/layout/list/layout_inline_list_item.h b/third_party/blink/renderer/core/layout/list/layout_inline_list_item.h
index b0d5025..b20319c6 100644
--- a/third_party/blink/renderer/core/layout/list/layout_inline_list_item.h
+++ b/third_party/blink/renderer/core/layout/list/layout_inline_list_item.h
@@ -30,7 +30,10 @@
  private:
   void WillBeDestroyed() override;
   const char* GetName() const override;
-  bool IsOfType(LayoutObjectType) const override;
+  bool IsInlineListItem() const final {
+    NOT_DESTROYED();
+    return true;
+  }
   void InsertedIntoTree() override;
   void WillBeRemovedFromTree() override;
   void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
diff --git a/third_party/blink/renderer/core/layout/list/layout_inside_list_marker.cc b/third_party/blink/renderer/core/layout/list/layout_inside_list_marker.cc
index f7fd463..5fbbbc0 100644
--- a/third_party/blink/renderer/core/layout/list/layout_inside_list_marker.cc
+++ b/third_party/blink/renderer/core/layout/list/layout_inside_list_marker.cc
@@ -12,11 +12,6 @@
 LayoutInsideListMarker::LayoutInsideListMarker(Element* element)
     : LayoutInline(element) {}
 
-bool LayoutInsideListMarker::IsOfType(LayoutObjectType type) const {
-  NOT_DESTROYED();
-  return type == kLayoutObjectInsideListMarker || LayoutInline::IsOfType(type);
-}
-
 PositionWithAffinity LayoutInsideListMarker::PositionForPoint(
     const PhysicalOffset&) const {
   NOT_DESTROYED();
diff --git a/third_party/blink/renderer/core/layout/list/layout_inside_list_marker.h b/third_party/blink/renderer/core/layout/list/layout_inside_list_marker.h
index eea30e4..3ef94f5 100644
--- a/third_party/blink/renderer/core/layout/list/layout_inside_list_marker.h
+++ b/third_party/blink/renderer/core/layout/list/layout_inside_list_marker.h
@@ -41,7 +41,10 @@
 #endif
 
  private:
-  bool IsOfType(LayoutObjectType) const override;
+  bool IsLayoutInsideListMarker() const final {
+    NOT_DESTROYED();
+    return true;
+  }
   PositionWithAffinity PositionForPoint(const PhysicalOffset&) const override;
 
   ListMarker list_marker_;
diff --git a/third_party/blink/renderer/core/layout/list/layout_list_item.cc b/third_party/blink/renderer/core/layout/list/layout_list_item.cc
index 1fab4e32..b3d54b04 100644
--- a/third_party/blink/renderer/core/layout/list/layout_list_item.cc
+++ b/third_party/blink/renderer/core/layout/list/layout_list_item.cc
@@ -26,10 +26,6 @@
   LayoutNGBlockFlow::WillBeDestroyed();
 }
 
-bool LayoutListItem::IsOfType(LayoutObjectType type) const {
-  return type == kLayoutObjectListItem || LayoutNGBlockFlow::IsOfType(type);
-}
-
 void LayoutListItem::InsertedIntoTree() {
   LayoutNGBlockFlow::InsertedIntoTree();
 
diff --git a/third_party/blink/renderer/core/layout/list/layout_list_item.h b/third_party/blink/renderer/core/layout/list/layout_list_item.h
index 56275b4..92cecb2 100644
--- a/third_party/blink/renderer/core/layout/list/layout_list_item.h
+++ b/third_party/blink/renderer/core/layout/list/layout_list_item.h
@@ -43,7 +43,10 @@
   }
 
  private:
-  bool IsOfType(LayoutObjectType) const override;
+  bool IsLayoutListItem() const final {
+    NOT_DESTROYED();
+    return true;
+  }
 
   void InsertedIntoTree() override;
   void WillBeRemovedFromTree() override;
diff --git a/third_party/blink/renderer/core/layout/list/layout_list_marker_image.cc b/third_party/blink/renderer/core/layout/list/layout_list_marker_image.cc
index 38e40fe3..86b8cee 100644
--- a/third_party/blink/renderer/core/layout/list/layout_list_marker_image.cc
+++ b/third_party/blink/renderer/core/layout/list/layout_list_marker_image.cc
@@ -21,11 +21,6 @@
   return object;
 }
 
-bool LayoutListMarkerImage::IsOfType(LayoutObjectType type) const {
-  NOT_DESTROYED();
-  return type == kLayoutObjectListMarkerImage || LayoutImage::IsOfType(type);
-}
-
 gfx::SizeF LayoutListMarkerImage::DefaultSize() const {
   NOT_DESTROYED();
   const SimpleFontData* font_data = Style()->GetFont().PrimaryFont();
diff --git a/third_party/blink/renderer/core/layout/list/layout_list_marker_image.h b/third_party/blink/renderer/core/layout/list/layout_list_marker_image.h
index 7a2328b..f871c3c 100644
--- a/third_party/blink/renderer/core/layout/list/layout_list_marker_image.h
+++ b/third_party/blink/renderer/core/layout/list/layout_list_marker_image.h
@@ -24,7 +24,10 @@
   gfx::SizeF DefaultSize() const;
 
  private:
-  bool IsOfType(LayoutObjectType) const override;
+  bool IsListMarkerImage() const final {
+    NOT_DESTROYED();
+    return true;
+  }
 
   void ComputeIntrinsicSizingInfoByDefaultSize(IntrinsicSizingInfo&) const;
   void ComputeIntrinsicSizingInfo(IntrinsicSizingInfo&) const final;
diff --git a/third_party/blink/renderer/core/layout/list/layout_outside_list_marker.cc b/third_party/blink/renderer/core/layout/list/layout_outside_list_marker.cc
index b55d26d..cb6ac9e 100644
--- a/third_party/blink/renderer/core/layout/list/layout_outside_list_marker.cc
+++ b/third_party/blink/renderer/core/layout/list/layout_outside_list_marker.cc
@@ -15,11 +15,6 @@
 LayoutOutsideListMarker::LayoutOutsideListMarker(Element* element)
     : LayoutNGBlockFlow(element) {}
 
-bool LayoutOutsideListMarker::IsOfType(LayoutObjectType type) const {
-  return type == kLayoutObjectOutsideListMarker ||
-         LayoutNGBlockFlow::IsOfType(type);
-}
-
 void LayoutOutsideListMarker::WillCollectInlines() {
   list_marker_.UpdateMarkerTextIfNeeded(*this);
 }
diff --git a/third_party/blink/renderer/core/layout/list/layout_outside_list_marker.h b/third_party/blink/renderer/core/layout/list/layout_outside_list_marker.h
index 8557d16..766cb981 100644
--- a/third_party/blink/renderer/core/layout/list/layout_outside_list_marker.h
+++ b/third_party/blink/renderer/core/layout/list/layout_outside_list_marker.h
@@ -37,7 +37,10 @@
   bool IsMonolithic() const final;
 
  private:
-  bool IsOfType(LayoutObjectType) const override;
+  bool IsLayoutOutsideListMarker() const final {
+    NOT_DESTROYED();
+    return true;
+  }
   PositionWithAffinity PositionForPoint(const PhysicalOffset&) const override;
 
   ListMarker list_marker_;
diff --git a/third_party/blink/renderer/core/layout/mathml/layout_mathml_block.cc b/third_party/blink/renderer/core/layout/mathml/layout_mathml_block.cc
index 4cf8b3e5..fd18df4 100644
--- a/third_party/blink/renderer/core/layout/mathml/layout_mathml_block.cc
+++ b/third_party/blink/renderer/core/layout/mathml/layout_mathml_block.cc
@@ -12,11 +12,9 @@
 
 LayoutMathMLBlock::LayoutMathMLBlock(Element* element) : LayoutBlock(element) {}
 
-bool LayoutMathMLBlock::IsOfType(LayoutObjectType type) const {
-  return type == kLayoutObjectMathML ||
-         (type == kLayoutObjectMathMLRoot && GetNode() &&
-          GetNode()->HasTagName(mathml_names::kMathTag)) ||
-         LayoutBlock::IsOfType(type);
+bool LayoutMathMLBlock::IsMathMLRoot() const {
+  NOT_DESTROYED();
+  return GetNode() && GetNode()->HasTagName(mathml_names::kMathTag);
 }
 
 bool LayoutMathMLBlock::IsChildAllowed(LayoutObject* child,
diff --git a/third_party/blink/renderer/core/layout/mathml/layout_mathml_block.h b/third_party/blink/renderer/core/layout/mathml/layout_mathml_block.h
index 882e56f..4e7dc87 100644
--- a/third_party/blink/renderer/core/layout/mathml/layout_mathml_block.h
+++ b/third_party/blink/renderer/core/layout/mathml/layout_mathml_block.h
@@ -19,7 +19,12 @@
   }
 
  private:
-  bool IsOfType(LayoutObjectType) const final;
+  bool IsMathML() const final {
+    NOT_DESTROYED();
+    return true;
+  }
+  bool IsMathMLRoot() const final;
+
   bool IsChildAllowed(LayoutObject*, const ComputedStyle&) const final;
   bool CanHaveChildren() const final;
   void StyleDidChange(StyleDifference, const ComputedStyle*) final;
diff --git a/third_party/blink/renderer/core/layout/mathml/layout_mathml_block_flow.cc b/third_party/blink/renderer/core/layout/mathml/layout_mathml_block_flow.cc
index 4a938c5..f7d87ca 100644
--- a/third_party/blink/renderer/core/layout/mathml/layout_mathml_block_flow.cc
+++ b/third_party/blink/renderer/core/layout/mathml/layout_mathml_block_flow.cc
@@ -11,8 +11,4 @@
   DCHECK(element);
 }
 
-bool LayoutMathMLBlockFlow::IsOfType(LayoutObjectType type) const {
-  return type == kLayoutObjectMathML || LayoutNGBlockFlow::IsOfType(type);
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/mathml/layout_mathml_block_flow.h b/third_party/blink/renderer/core/layout/mathml/layout_mathml_block_flow.h
index be3b21f..05b755c 100644
--- a/third_party/blink/renderer/core/layout/mathml/layout_mathml_block_flow.h
+++ b/third_party/blink/renderer/core/layout/mathml/layout_mathml_block_flow.h
@@ -21,7 +21,10 @@
   }
 
  private:
-  bool IsOfType(LayoutObjectType) const final;
+  bool IsMathML() const final {
+    NOT_DESTROYED();
+    return true;
+  }
   bool IsChildAllowed(LayoutObject*, const ComputedStyle&) const final {
     NOT_DESTROYED();
     return true;
diff --git a/third_party/blink/renderer/core/layout/min_max_size_test.cc b/third_party/blink/renderer/core/layout/min_max_size_test.cc
index 43ea8e4a..d203b8d 100644
--- a/third_party/blink/renderer/core/layout/min_max_size_test.cc
+++ b/third_party/blink/renderer/core/layout/min_max_size_test.cc
@@ -2,15 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/core/layout/min_max_sizes.h"
-
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/layout/min_max_sizes.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
 
 namespace blink {
 
 namespace {
 
 TEST(MinMaxSizesTest, ShrinkToFit) {
+  test::TaskEnvironment task_environment;
   MinMaxSizes sizes;
 
   sizes.min_size = LayoutUnit(100);
diff --git a/third_party/blink/renderer/core/layout/min_max_sizes_cache_test.cc b/third_party/blink/renderer/core/layout/min_max_sizes_cache_test.cc
index 371cafd..059be5a 100644
--- a/third_party/blink/renderer/core/layout/min_max_sizes_cache_test.cc
+++ b/third_party/blink/renderer/core/layout/min_max_sizes_cache_test.cc
@@ -5,12 +5,14 @@
 #include "third_party/blink/renderer/core/layout/min_max_sizes_cache.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
 
 namespace blink {
 
 namespace {
 
 TEST(MinMaxSizesCacheTest, Eviction) {
+  test::TaskEnvironment task_environment;
   auto* cache = MakeGarbageCollected<MinMaxSizesCache>();
 
   // Populate the cache with the max number of entries.
diff --git a/third_party/blink/renderer/core/layout/outline_rect_collector_test.cc b/third_party/blink/renderer/core/layout/outline_rect_collector_test.cc
index f2361f5..9313b4a 100644
--- a/third_party/blink/renderer/core/layout/outline_rect_collector_test.cc
+++ b/third_party/blink/renderer/core/layout/outline_rect_collector_test.cc
@@ -7,10 +7,12 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
 #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
 
 namespace blink {
 
 TEST(OutlineRectCollectorTest, Empty) {
+  test::TaskEnvironment task_environment;
   UnionOutlineRectCollector u;
   VectorOutlineRectCollector v;
 
@@ -19,6 +21,7 @@
 }
 
 TEST(OutlineRectCollectorTest, AddRect) {
+  test::TaskEnvironment task_environment;
   Vector<Vector<PhysicalRect>> tests = {
       Vector<PhysicalRect>{
           PhysicalRect(-1, -1, 10, 10), PhysicalRect(10, 20, 30, 40),
@@ -52,6 +55,7 @@
 }
 
 TEST(OutlineRectCollectorTest, CombineWithOffset) {
+  test::TaskEnvironment task_environment;
   UnionOutlineRectCollector u;
   VectorOutlineRectCollector v;
 
diff --git a/third_party/blink/renderer/core/layout/overflow_model_test.cc b/third_party/blink/renderer/core/layout/overflow_model_test.cc
index 51e0e840..1298057 100644
--- a/third_party/blink/renderer/core/layout/overflow_model_test.cc
+++ b/third_party/blink/renderer/core/layout/overflow_model_test.cc
@@ -32,6 +32,7 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
 
 namespace blink {
 namespace {
@@ -49,6 +50,7 @@
   BoxOverflowModelTest()
       : scrollable_overflow_(InitialScrollableOverflow()),
         visual_overflow_(InitialVisualOverflow()) {}
+  test::TaskEnvironment task_environment_;
   BoxScrollableOverflowModel scrollable_overflow_;
   BoxVisualOverflowModel visual_overflow_;
 };
diff --git a/third_party/blink/renderer/core/layout/relative_utils_test.cc b/third_party/blink/renderer/core/layout/relative_utils_test.cc
index 5cd177e..deb6d98 100644
--- a/third_party/blink/renderer/core/layout/relative_utils_test.cc
+++ b/third_party/blink/renderer/core/layout/relative_utils_test.cc
@@ -8,6 +8,7 @@
 #include "third_party/blink/renderer/core/layout/geometry/physical_offset.h"
 #include "third_party/blink/renderer/core/layout/geometry/physical_size.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
 
 namespace blink {
 namespace {
@@ -42,6 +43,7 @@
   }
 
   Persistent<const ComputedStyle> initial_style_;
+  test::TaskEnvironment task_environment_;
   LogicalSize container_size_;
 };
 
diff --git a/third_party/blink/renderer/core/layout/scroll_anchor_test.cc b/third_party/blink/renderer/core/layout/scroll_anchor_test.cc
index 5576ad0..07820b9 100644
--- a/third_party/blink/renderer/core/layout/scroll_anchor_test.cc
+++ b/third_party/blink/renderer/core/layout/scroll_anchor_test.cc
@@ -27,6 +27,7 @@
 #include "third_party/blink/renderer/core/testing/sim/sim_test.h"
 #include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
 
 namespace blink {
@@ -1123,6 +1124,7 @@
   const int FAKE_FIND_ID = 1;
 
  private:
+  test::TaskEnvironment task_environment_;
   frame_test_helpers::WebViewHelper web_view_helper_;
 };
 
diff --git a/third_party/blink/renderer/core/layout/scrollbars_test.cc b/third_party/blink/renderer/core/layout/scrollbars_test.cc
index 94892d5..9386de8 100644
--- a/third_party/blink/renderer/core/layout/scrollbars_test.cc
+++ b/third_party/blink/renderer/core/layout/scrollbars_test.cc
@@ -30,6 +30,7 @@
 #include "third_party/blink/renderer/core/testing/sim/sim_request.h"
 #include "third_party/blink/renderer/core/testing/sim/sim_test.h"
 #include "third_party/blink/renderer/platform/testing/paint_test_configurations.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
 #include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
 #include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
@@ -362,6 +363,7 @@
 }
 
 TEST(ScrollbarsTestWithOwnWebViewHelper, ScrollbarSizeF) {
+  test::TaskEnvironment task_environment;
   ScopedTestingPlatformSupport<TestingPlatformSupport> platform;
   frame_test_helpers::WebViewHelper web_view_helper;
   // Needed so visual viewport supplies its own scrollbars. We don't support
diff --git a/third_party/blink/renderer/core/layout/selection_state_test.cc b/third_party/blink/renderer/core/layout/selection_state_test.cc
index b9e583ad..8edee99 100644
--- a/third_party/blink/renderer/core/layout/selection_state_test.cc
+++ b/third_party/blink/renderer/core/layout/selection_state_test.cc
@@ -5,11 +5,14 @@
 #include "third_party/blink/renderer/core/layout/selection_state.h"
 
 #include <sstream>
+
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
 
 namespace blink {
 
 TEST(SelectionStateTest, StreamOutput) {
+  test::TaskEnvironment task_environment;
   // Just explicitly sanity check a couple of values.
   {
     std::stringstream string_stream;
diff --git a/third_party/blink/renderer/core/layout/shapes/box_shape_test.cc b/third_party/blink/renderer/core/layout/shapes/box_shape_test.cc
index b370454..cddf5b7e 100644
--- a/third_party/blink/renderer/core/layout/shapes/box_shape_test.cc
+++ b/third_party/blink/renderer/core/layout/shapes/box_shape_test.cc
@@ -30,9 +30,11 @@
 #include "third_party/blink/renderer/core/layout/shapes/box_shape.h"
 
 #include <memory>
+
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
 #include "third_party/blink/renderer/platform/geometry/float_rounded_rect.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
 
 namespace blink {
 
@@ -45,6 +47,7 @@
     return Shape::CreateLayoutBoxShape(bounds, WritingMode::kHorizontalTb,
                                        shape_margin);
   }
+  test::TaskEnvironment task_environment_;
 };
 
 namespace {
diff --git a/third_party/blink/renderer/core/layout/shapes/ellipse_shape_test.cc b/third_party/blink/renderer/core/layout/shapes/ellipse_shape_test.cc
index f020ee3..4e256d14 100644
--- a/third_party/blink/renderer/core/layout/shapes/ellipse_shape_test.cc
+++ b/third_party/blink/renderer/core/layout/shapes/ellipse_shape_test.cc
@@ -6,6 +6,7 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
 
 namespace blink {
 
@@ -29,6 +30,7 @@
   } while (false)
 
 TEST(EllipseShapeTest, ZeroRadii) {
+  test::TaskEnvironment task_environment;
   EllipseShape shape(gfx::PointF(), 0, 0);
   EXPECT_TRUE(shape.IsEmpty());
   EXPECT_EQ(LogicalRect(), shape.ShapeMarginLogicalBoundingBox());
@@ -37,6 +39,7 @@
 }
 
 TEST(EllipseShapeTest, ZeroRadiusX) {
+  test::TaskEnvironment task_environment;
   EllipseShape shape(gfx::PointF(), 0, 10);
   EXPECT_TRUE(shape.IsEmpty());
   EXPECT_EQ(LogicalRect(0, -10, 0, 20), shape.ShapeMarginLogicalBoundingBox());
@@ -45,6 +48,7 @@
 }
 
 TEST(EllipseShapeTest, ZeroRadiusY) {
+  test::TaskEnvironment task_environment;
   EllipseShape shape(gfx::PointF(), 10, 0);
   EXPECT_TRUE(shape.IsEmpty());
   EXPECT_EQ(LogicalRect(-10, 0, 20, 0), shape.ShapeMarginLogicalBoundingBox());
@@ -53,6 +57,7 @@
 }
 
 TEST(EllipseShapeTest, ZeroRadiiWithMargin) {
+  test::TaskEnvironment task_environment;
   EllipseShape shape(gfx::PointF(10, 20), 0, 0);
   shape.SetShapeMarginForTesting(5);
   EXPECT_TRUE(shape.IsEmpty());
@@ -80,6 +85,7 @@
 }
 
 TEST(EllipseShapeTest, NonZeroRadiiWithMargin) {
+  test::TaskEnvironment task_environment;
   EllipseShape shape(gfx::PointF(10, 20), 20, 10);
   shape.SetShapeMarginForTesting(5);
   EXPECT_FALSE(shape.IsEmpty());
@@ -107,6 +113,7 @@
 }
 
 TEST(EllipseShapeTest, ShapeMarginLogicalBoundingBoxWithFloatValues) {
+  test::TaskEnvironment task_environment;
   EXPECT_EQ(LogicalRect(LayoutUnit(-2.25f), LayoutUnit(-2.125f), LayoutUnit(7),
                         LayoutUnit(9.75f)),
             EllipseShape(gfx::PointF(1.25f, 2.75f), 3.5f, 4.875f)
diff --git a/third_party/blink/renderer/core/layout/shapes/shape.cc b/third_party/blink/renderer/core/layout/shapes/shape.cc
index 9d998d9..9553b8d 100644
--- a/third_party/blink/renderer/core/layout/shapes/shape.cc
+++ b/third_party/blink/renderer/core/layout/shapes/shape.cc
@@ -237,7 +237,7 @@
   }
 
   // Set |surface| to draw directly to |contents|.
-  const SkSurfaceProps disable_lcd_props(0, kUnknown_SkPixelGeometry);
+  const SkSurfaceProps disable_lcd_props;
   sk_sp<SkSurface> surface = SkSurfaces::WrapPixels(
       dst_info, contents.Data(), dst_info.minRowBytes(), &disable_lcd_props);
   if (!surface)
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_block.h b/third_party/blink/renderer/core/layout/svg/layout_svg_block.h
index 4ee673b..86f4d06e 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_block.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_block.h
@@ -76,9 +76,9 @@
   bool needs_transform_update_ : 1;
   bool transform_uses_reference_box_ : 1;
 
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsSVG() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectSVG || LayoutNGBlockFlow::IsOfType(type);
+    return true;
   }
 
   bool CheckForImplicitTransformChange(bool bbox_changed) const;
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_container.h b/third_party/blink/renderer/core/layout/svg/layout_svg_container.h
index 0594260..3467682f 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_container.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_container.h
@@ -96,10 +96,9 @@
     return content_;
   }
 
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsSVGContainer() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectSVGContainer ||
-           LayoutSVGModelObject::IsOfType(type);
+    return true;
   }
   void UpdateLayout() override;
   // Update LayoutObject state after layout has completed. Returns true if
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_filter_primitive.h b/third_party/blink/renderer/core/layout/svg/layout_svg_filter_primitive.h
index 5a51d98..121208c8 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_filter_primitive.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_filter_primitive.h
@@ -51,11 +51,13 @@
     NOT_DESTROYED();
     return "LayoutSVGFilterPrimitive";
   }
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsSVG() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectSVG ||
-           type == kLayoutObjectSVGFilterPrimitive ||
-           LayoutObject::IsOfType(type);
+    return true;
+  }
+  bool IsSVGFilterPrimitive() const final {
+    NOT_DESTROYED();
+    return true;
   }
   gfx::RectF ObjectBoundingBox() const override {
     NOT_DESTROYED();
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.cc
index 586dbec..8083b6a7 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.cc
@@ -25,12 +25,6 @@
   return "LayoutSVGForeignObject";
 }
 
-bool LayoutSVGForeignObject::IsOfType(LayoutObjectType type) const {
-  NOT_DESTROYED();
-  return type == kLayoutObjectSVGForeignObject ||
-         LayoutSVGBlock::IsOfType(type);
-}
-
 bool LayoutSVGForeignObject::IsChildAllowed(LayoutObject* child,
                                             const ComputedStyle& style) const {
   NOT_DESTROYED();
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h b/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h
index 4d73f6fe..703bace 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h
@@ -54,7 +54,10 @@
   // boundaries needs to be propagated (because of a change to the transform).
   bool UpdateAfterSvgLayout(bool bounds_changed);
   const char* GetName() const override;
-  bool IsOfType(LayoutObjectType type) const override;
+  bool IsSVGForeignObject() const final {
+    NOT_DESTROYED();
+    return true;
+  }
   bool IsChildAllowed(LayoutObject* child,
                       const ComputedStyle& style) const override;
   gfx::RectF ObjectBoundingBox() const override;
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.h b/third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.h
index 22d9119f..96c07d04 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.h
@@ -42,10 +42,9 @@
  protected:
   void UpdateLayout() override;
 
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsSVGHiddenContainer() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectSVGHiddenContainer ||
-           LayoutSVGContainer::IsOfType(type);
+    return true;
   }
 
  private:
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_image.h b/third_party/blink/renderer/core/layout/svg/layout_svg_image.h
index 4a6d69da..3036dcb 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_image.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_image.h
@@ -62,10 +62,9 @@
     return !object_bounding_box_.IsEmpty();
   }
 
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsSVGImage() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectSVGImage ||
-           LayoutSVGModelObject::IsOfType(type);
+    return true;
   }
 
   AffineTransform LocalSVGTransform() const override {
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_inline.h b/third_party/blink/renderer/core/layout/svg/layout_svg_inline.h
index ccf785c1..b7012c45 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_inline.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_inline.h
@@ -39,10 +39,13 @@
     NOT_DESTROYED();
     return kNoPaintLayer;
   }
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsSVG() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectSVG || type == kLayoutObjectSVGInline ||
-           LayoutInline::IsOfType(type);
+    return true;
+  }
+  bool IsSVGInline() const final {
+    NOT_DESTROYED();
+    return true;
   }
 
   bool IsChildAllowed(LayoutObject*, const ComputedStyle&) const override;
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.h b/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.h
index 2acd45f..76a8238 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.h
@@ -57,10 +57,13 @@
 
   gfx::RectF ObjectBoundingBox() const override;
 
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsSVG() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectSVG || type == kLayoutObjectSVGInlineText ||
-           LayoutText::IsOfType(type);
+    return true;
+  }
+  bool IsSVGInlineText() const final {
+    NOT_DESTROYED();
+    return true;
   }
 
   PhysicalRect PhysicalLinesBoundingBox() const override;
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.h b/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.h
index d65a763..8f13762f 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.h
@@ -72,9 +72,9 @@
     return To<SVGElement>(LayoutObject::GetNode());
   }
 
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsSVG() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectSVG || LayoutObject::IsOfType(type);
+    return true;
   }
 
  protected:
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h
index b3a3bce..95065dd 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h
@@ -60,10 +60,9 @@
   }
 
   void UpdateLayout() override;
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsSVGResourceContainer() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectSVGResourceContainer ||
-           LayoutSVGHiddenContainer::IsOfType(type);
+    return true;
   }
 
   virtual LayoutSVGResourceType ResourceType() const = 0;
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_root.h b/third_party/blink/renderer/core/layout/svg/layout_svg_root.h
index 4ae4583..1cfa33a 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_root.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_root.h
@@ -134,10 +134,13 @@
     return &content_.Children();
   }
 
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsSVG() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectSVG || type == kLayoutObjectSVGRoot ||
-           LayoutReplaced::IsOfType(type);
+    return true;
+  }
+  bool IsSVGRoot() const final {
+    NOT_DESTROYED();
+    return true;
   }
 
   void ComputeIntrinsicSizingInfo(IntrinsicSizingInfo&) const override;
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h b/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h
index 89d1100..72e5410d 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h
@@ -183,10 +183,9 @@
                     const WindRule fill_rule = RULE_NONZERO);
   bool StrokeContains(const HitTestLocation&, bool requires_stroke = true);
 
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsSVGShape() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectSVGShape ||
-           LayoutSVGModelObject::IsOfType(type);
+    return true;
   }
   void UpdateLayout() final;
   // Update LayoutObject state after layout has completed. Returns true if
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
index 24026527..7934028 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
@@ -78,11 +78,6 @@
   return "LayoutSVGText";
 }
 
-bool LayoutSVGText::IsOfType(LayoutObjectType type) const {
-  NOT_DESTROYED();
-  return type == kLayoutObjectSVGText || LayoutSVGBlock::IsOfType(type);
-}
-
 bool LayoutSVGText::CreatesNewFormattingContext() const {
   NOT_DESTROYED();
   return true;
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_text.h b/third_party/blink/renderer/core/layout/svg/layout_svg_text.h
index a54a1d9..7eee8065 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_text.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_text.h
@@ -38,7 +38,10 @@
   // boundaries needs to be propagated (because of a change to the transform).
   bool UpdateAfterSvgLayout(bool bounds_changed);
   const char* GetName() const override;
-  bool IsOfType(LayoutObjectType type) const override;
+  bool IsSVGText() const final {
+    NOT_DESTROYED();
+    return true;
+  }
   bool IsChildAllowed(LayoutObject* child, const ComputedStyle&) const override;
   void AddChild(LayoutObject* child, LayoutObject* before_child) override;
   void RemoveChild(LayoutObject* child) override;
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_text_path.h b/third_party/blink/renderer/core/layout/svg/layout_svg_text_path.h
index 8ddf0bb..e4b0718 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_text_path.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_text_path.h
@@ -64,9 +64,9 @@
 
   bool IsChildAllowed(LayoutObject*, const ComputedStyle&) const override;
 
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsSVGTextPath() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectSVGTextPath || LayoutSVGInline::IsOfType(type);
+    return true;
   }
 
   const char* GetName() const override {
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_transformable_container.h b/third_party/blink/renderer/core/layout/svg/layout_svg_transformable_container.h
index 3a4f355..27fbed1 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_transformable_container.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_transformable_container.h
@@ -34,10 +34,9 @@
 
   bool IsChildAllowed(LayoutObject*, const ComputedStyle&) const override;
 
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsSVGTransformableContainer() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectSVGTransformableContainer ||
-           LayoutSVGContainer::IsOfType(type);
+    return true;
   }
   const gfx::Vector2dF& AdditionalTranslation() const {
     NOT_DESTROYED();
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_tspan.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_tspan.cc
index 3864836..5f9c2e0 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_tspan.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_tspan.cc
@@ -28,11 +28,6 @@
 
 LayoutSVGTSpan::LayoutSVGTSpan(Element* element) : LayoutSVGInline(element) {}
 
-bool LayoutSVGTSpan::IsOfType(LayoutObjectType type) const {
-  NOT_DESTROYED();
-  return type == kLayoutObjectSVGTSpan || LayoutSVGInline::IsOfType(type);
-}
-
 bool LayoutSVGTSpan::IsChildAllowed(LayoutObject* child,
                                     const ComputedStyle&) const {
   NOT_DESTROYED();
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_tspan.h b/third_party/blink/renderer/core/layout/svg/layout_svg_tspan.h
index 9349feec..ea4a5966 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_tspan.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_tspan.h
@@ -29,7 +29,10 @@
  public:
   explicit LayoutSVGTSpan(Element*);
 
-  bool IsOfType(LayoutObjectType type) const override;
+  bool IsSVGTSpan() const final {
+    NOT_DESTROYED();
+    return true;
+  }
   bool IsChildAllowed(LayoutObject*, const ComputedStyle&) const override;
 
   const char* GetName() const override {
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.h b/third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.h
index a50c161..df80b3bc 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.h
@@ -56,10 +56,9 @@
   gfx::RectF ViewBoxRect() const;
 
  private:
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsSVGViewportContainer() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectSVGViewportContainer ||
-           LayoutSVGContainer::IsOfType(type);
+    return true;
   }
 
   void UpdateLayout() override;
diff --git a/third_party/blink/renderer/core/layout/table/layout_table.h b/third_party/blink/renderer/core/layout/table/layout_table.h
index a343c49..8e95a4b5 100644
--- a/third_party/blink/renderer/core/layout/table/layout_table.h
+++ b/third_party/blink/renderer/core/layout/table/layout_table.h
@@ -205,9 +205,9 @@
   unsigned EffectiveColumnCount() const;
 
  protected:
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsTable() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectTable || LayoutBlock::IsOfType(type);
+    return true;
   }
 
   // Table paints background specially.
diff --git a/third_party/blink/renderer/core/layout/table/layout_table_caption.h b/third_party/blink/renderer/core/layout/table/layout_table_caption.h
index aed70bb..fd1a8e48 100644
--- a/third_party/blink/renderer/core/layout/table/layout_table_caption.h
+++ b/third_party/blink/renderer/core/layout/table/layout_table_caption.h
@@ -24,10 +24,9 @@
     return true;
   }
 
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsTableCaption() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectTableCaption ||
-           LayoutNGBlockFlow::IsOfType(type);
+    return true;
   }
 };
 
diff --git a/third_party/blink/renderer/core/layout/table/layout_table_cell.h b/third_party/blink/renderer/core/layout/table/layout_table_cell.h
index 6410cf7..f35bf799 100644
--- a/third_party/blink/renderer/core/layout/table/layout_table_cell.h
+++ b/third_party/blink/renderer/core/layout/table/layout_table_cell.h
@@ -101,9 +101,9 @@
   unsigned ColSpan() const;
 
  protected:
-  bool IsOfType(LayoutObjectType type) const final {
+  bool IsTableCell() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectTableCell || LayoutNGBlockFlow::IsOfType(type);
+    return true;
   }
 
   // Table cell applies a special clip to its background.
diff --git a/third_party/blink/renderer/core/layout/table/layout_table_column.h b/third_party/blink/renderer/core/layout/table/layout_table_column.h
index 0ea0b1e..b8d20e2 100644
--- a/third_party/blink/renderer/core/layout/table/layout_table_column.h
+++ b/third_party/blink/renderer/core/layout/table/layout_table_column.h
@@ -83,9 +83,9 @@
   }
 
  protected:
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsLayoutTableCol() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectTableCol || LayoutBox::IsOfType(type);
+    return true;
   }
 
   // Table row doesn't paint background by itself.
diff --git a/third_party/blink/renderer/core/layout/table/layout_table_row.h b/third_party/blink/renderer/core/layout/table/layout_table_row.h
index 8fd55d0a..21be385 100644
--- a/third_party/blink/renderer/core/layout/table/layout_table_row.h
+++ b/third_party/blink/renderer/core/layout/table/layout_table_row.h
@@ -83,9 +83,9 @@
   unsigned RowIndex() const;
 
  protected:
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsTableRow() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectTableRow || LayoutBlock::IsOfType(type);
+    return true;
   }
 
   // Table section paints background specially.
diff --git a/third_party/blink/renderer/core/layout/table/layout_table_section.h b/third_party/blink/renderer/core/layout/table/layout_table_section.h
index f5765f5..4634ab09 100644
--- a/third_party/blink/renderer/core/layout/table/layout_table_section.h
+++ b/third_party/blink/renderer/core/layout/table/layout_table_section.h
@@ -77,9 +77,9 @@
   unsigned NumRows() const;
 
  protected:
-  bool IsOfType(LayoutObjectType type) const override {
+  bool IsTableSection() const final {
     NOT_DESTROYED();
-    return type == kLayoutObjectTableSection || LayoutBlock::IsOfType(type);
+    return true;
   }
 
   // Table section paints background specially.
diff --git a/third_party/blink/renderer/core/loader/render_blocking_resource_manager.cc b/third_party/blink/renderer/core/loader/render_blocking_resource_manager.cc
index 0a513b4..b3ca7d10 100644
--- a/third_party/blink/renderer/core/loader/render_blocking_resource_manager.cc
+++ b/third_party/blink/renderer/core/loader/render_blocking_resource_manager.cc
@@ -159,6 +159,7 @@
   } else {
     it->value->insert(link);
   }
+  document_->SetHasRenderBlockingExpectLinkElements(true);
 }
 
 void RenderBlockingResourceManager::RemovePendingParsingElement(
@@ -173,6 +174,7 @@
 
   element_render_blocking_links_.erase(id);
   if (element_render_blocking_links_.empty()) {
+    document_->SetHasRenderBlockingExpectLinkElements(false);
     RenderBlockingResourceUnblocked();
   }
 }
@@ -200,6 +202,7 @@
   }
 
   if (element_render_blocking_links_.empty()) {
+    document_->SetHasRenderBlockingExpectLinkElements(false);
     RenderBlockingResourceUnblocked();
   }
 }
@@ -213,6 +216,7 @@
     return;
   }
 
+  document_->SetHasRenderBlockingExpectLinkElements(false);
   element_render_blocking_links_.clear();
   RenderBlockingResourceUnblocked();
 }
diff --git a/third_party/blink/renderer/core/origin_trials/origin_trial_context.cc b/third_party/blink/renderer/core/origin_trials/origin_trial_context.cc
index 72e6609..79b2188 100644
--- a/third_party/blink/renderer/core/origin_trials/origin_trial_context.cc
+++ b/third_party/blink/renderer/core/origin_trials/origin_trial_context.cc
@@ -8,7 +8,6 @@
 #include <vector>
 
 #include "base/feature_list.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/time/time.h"
 #include "components/attribution_reporting/features.h"
 #include "services/network/public/cpp/attribution_reporting_runtime_features.h"
@@ -35,7 +34,6 @@
 #include "third_party/blink/renderer/core/workers/worklet_global_scope.h"
 #include "third_party/blink/renderer/platform/bindings/origin_trial_features.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
-#include "third_party/blink/renderer/platform/instrumentation/histogram.h"
 #include "third_party/blink/renderer/platform/runtime_feature_state/runtime_feature_state_override_context.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
@@ -49,10 +47,6 @@
 
 constexpr char kDefaultTrialName[] = "UNKNOWN";
 
-void RecordTokenValidationResultHistogram(OriginTrialTokenStatus status) {
-  UMA_HISTOGRAM_ENUMERATION("OriginTrials.ValidationResult", status);
-}
-
 bool IsWhitespace(UChar chr) {
   return (chr == ' ') || (chr == '\t');
 }
@@ -723,7 +717,6 @@
                        script_origins);
   }
 
-  RecordTokenValidationResultHistogram(token_result.Status());
   CacheToken(token, token_result, trial_status);
   return trial_status == OriginTrialStatus::kEnabled;
 }
diff --git a/third_party/blink/renderer/core/origin_trials/origin_trial_context_test.cc b/third_party/blink/renderer/core/origin_trials/origin_trial_context_test.cc
index 571a0db8..4a1918e6 100644
--- a/third_party/blink/renderer/core/origin_trials/origin_trial_context_test.cc
+++ b/third_party/blink/renderer/core/origin_trials/origin_trial_context_test.cc
@@ -9,7 +9,6 @@
 
 #include "base/containers/span.h"
 #include "base/ranges/algorithm.h"
-#include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/time/time.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -53,9 +52,6 @@
 // The tokens expire in 2033.
 const base::Time kBaseTokenExpiryTime = base::Time::FromTimeT(2000000000);
 
-// Names of UMA histograms
-const char kResultHistogram[] = "OriginTrials.ValidationResult";
-
 // Trial token placeholder for mocked calls to validator
 const char kTokenPlaceholder[] = "The token contents are not used";
 
@@ -198,34 +194,12 @@
         ->IsNavigationFeatureActivated(feature);
   }
 
-  void ExpectStatusCount(OriginTrialTokenStatus status, int count) {
-    histogram_tester_.ExpectBucketCount(kResultHistogram,
-                                        static_cast<int>(status), count);
-  }
-
-  void ExpectStatusTotalMetric(int total) {
-    histogram_tester_.ExpectTotalCount(kResultHistogram, total);
-  }
-
  protected:
   test::TaskEnvironment task_environment_;
   MockTokenValidator* token_validator_;
   Persistent<NullExecutionContext> execution_context_;
-  base::HistogramTester histogram_tester_;
 };
 
-// Check that validation status gets logged to the histogram
-// on both success and failure
-TEST_F(OriginTrialContextTest, ValidationStatusLoggedInHistogram) {
-  UpdateSecurityOrigin(kFrobulateEnabledOrigin);
-  AddTokenWithResponse(kFrobulateTrialName, OriginTrialTokenStatus::kSuccess);
-  AddTokenWithResponse(kUnknownTrialName,
-                       OriginTrialTokenStatus::kUnknownTrial);
-  ExpectStatusCount(OriginTrialTokenStatus::kSuccess, 1);
-  ExpectStatusCount(OriginTrialTokenStatus::kUnknownTrial, 1);
-  ExpectStatusTotalMetric(2);
-}
-
 // Test that we're passing correct information to the validator
 TEST_F(OriginTrialContextTest, ValidatorGetsCorrectInfo) {
   UpdateSecurityOrigin(kFrobulateEnabledOrigin);
diff --git a/third_party/blink/renderer/core/paint/timing/text_paint_timing_detector.cc b/third_party/blink/renderer/core/paint/timing/text_paint_timing_detector.cc
index cee69fe..45394af 100644
--- a/third_party/blink/renderer/core/paint/timing/text_paint_timing_detector.cc
+++ b/third_party/blink/renderer/core/paint/timing/text_paint_timing_detector.cc
@@ -179,8 +179,7 @@
   // Web font styled node should be rewalkable so that resizing during swap
   // would make the node eligible to be LCP candidate again.
   if (RuntimeEnabledFeatures::WebFontResizeLCPEnabled()) {
-    if (aggregator.GetNode()->GetComputedStyle() &&
-        aggregator.GetNode()->GetComputedStyle()->GetFont().HasCustomFont()) {
+    if (aggregator.StyleRef().GetFont().HasCustomFont()) {
       rewalkable_set_.insert(&aggregator);
     }
   }
diff --git a/third_party/blink/renderer/core/testing/page_test_base.cc b/third_party/blink/renderer/core/testing/page_test_base.cc
index 8254830..07329f0 100644
--- a/third_party/blink/renderer/core/testing/page_test_base.cc
+++ b/third_party/blink/renderer/core/testing/page_test_base.cc
@@ -104,8 +104,7 @@
 PageTestBase::PageTestBase() = default;
 
 PageTestBase::PageTestBase(base::test::TaskEnvironment::TimeSource time_source)
-    : task_environment_(time_source,
-                        test::TaskEnvironment::RealMainThreadScheduler()) {}
+    : task_environment_(time_source) {}
 
 PageTestBase::~PageTestBase() {
   dummy_page_holder_.reset();
diff --git a/third_party/blink/renderer/core/testing/page_test_base.h b/third_party/blink/renderer/core/testing/page_test_base.h
index 6af4f62..cd6d22f 100644
--- a/third_party/blink/renderer/core/testing/page_test_base.h
+++ b/third_party/blink/renderer/core/testing/page_test_base.h
@@ -144,8 +144,7 @@
   void AdvanceClock(base::TimeDelta);
 
  private:
-  test::TaskEnvironment task_environment_{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment_;
   // The order is important: |platform_| must be destroyed after
   // |dummy_page_holder_| is destroyed.
   std::unique_ptr<ScopedTestingPlatformSupport<TestingPlatformSupport>>
diff --git a/third_party/blink/renderer/core/testing/sim/sim_test.h b/third_party/blink/renderer/core/testing/sim/sim_test.h
index 8b669c4d..3061be6 100644
--- a/third_party/blink/renderer/core/testing/sim/sim_test.h
+++ b/third_party/blink/renderer/core/testing/sim/sim_test.h
@@ -78,8 +78,7 @@
   void SetPreferCompositingToLCDText(bool enabled);
 
  private:
-  test::TaskEnvironment task_environment_{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment_;
   // These are unique_ptrs in order to destroy them in TearDown. Subclasses
   // may override Platform::Current() and these must shutdown before the
   // subclass destructor.
diff --git a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h
index 555e83d0..64410c42 100644
--- a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h
+++ b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h
@@ -44,7 +44,7 @@
 
 // This class contains the logic for calculating Single-Page-App soft navigation
 // heuristics. See https://github.com/WICG/soft-navigations
-class SoftNavigationHeuristics
+class CORE_EXPORT SoftNavigationHeuristics
     : public GarbageCollected<SoftNavigationHeuristics>,
       public Supplement<LocalDOMWindow>,
       public scheduler::TaskAttributionTracker::Observer {
@@ -87,6 +87,10 @@
   // current_event_parameters_ and return true. Otherwise, return false.
   bool PopNestedEventParametersIfNeeded();
 
+  bool GetInitialInteractionEncounteredForTest() {
+    return initial_interaction_encountered_;
+  }
+
  private:
   enum FlagType : uint8_t {
     kURLChange,
diff --git a/third_party/blink/renderer/core/timing/soft_navigation_heuristics_test.cc b/third_party/blink/renderer/core/timing/soft_navigation_heuristics_test.cc
index 25c3b2a..0c11229 100644
--- a/third_party/blink/renderer/core/timing/soft_navigation_heuristics_test.cc
+++ b/third_party/blink/renderer/core/timing/soft_navigation_heuristics_test.cc
@@ -7,9 +7,51 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/time/time.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
+#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
+#include "third_party/blink/renderer/platform/bindings/script_state.h"
 
 namespace blink {
-using SoftNavigationHeuristicsTest = testing::Test;
+
+class SoftNavigationHeuristicsTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    page_holder_ = std::make_unique<DummyPageHolder>(gfx::Size(800, 600));
+  }
+
+  SoftNavigationHeuristics* CreateSoftNavigationHeuristicsForTest() {
+    ScriptState* script_state = GetScriptStateForTest();
+
+    LocalDOMWindow* window = LocalDOMWindow::From(script_state);
+
+    SoftNavigationHeuristics* heuristics =
+        SoftNavigationHeuristics::From(*window);
+
+    return heuristics;
+  }
+
+  ScriptState* GetScriptStateForTest() {
+    return ToScriptStateForMainWorld(page_holder_->GetDocument().GetFrame());
+  }
+
+ private:
+  std::unique_ptr<DummyPageHolder> page_holder_;
+};
+
+// TODO(crbug.com/1503284): This test validates that the renderer does not crash
+// when presented with an unset timestamp. Figure out whether it is possible to
+// void ever calling InteractionCallbackCalled in that situation instead.
+TEST_F(SoftNavigationHeuristicsTest,
+       EarlyReturnOnInvalidPendingInteractionTimestamp) {
+  auto* test_heuristics = CreateSoftNavigationHeuristicsForTest();
+  test_heuristics->InteractionCallbackCalled(
+      GetScriptStateForTest(), SoftNavigationHeuristics::EventScopeType::Click,
+      true);
+  // Since pending_interaction_timestamp_ is not set, the execution of
+  // InteractionCallbackCalled would return early. As a result, the
+  // initial_interaction_encountered_ would not be set true.
+  ASSERT_FALSE(test_heuristics->GetInitialInteractionEncounteredForTest());
+}
 
 TEST_F(SoftNavigationHeuristicsTest, UmaHistogramRecording) {
   base::HistogramTester histogram_tester;
diff --git a/third_party/blink/renderer/core/view_transition/view_transition_test.cc b/third_party/blink/renderer/core/view_transition/view_transition_test.cc
index 89a36af..913da0d 100644
--- a/third_party/blink/renderer/core/view_transition/view_transition_test.cc
+++ b/third_party/blink/renderer/core/view_transition/view_transition_test.cc
@@ -188,8 +188,7 @@
   }
 
  protected:
-  test::TaskEnvironment task_environment_{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment;
 
   std::unique_ptr<frame_test_helpers::WebViewHelper> web_view_helper_;
 };
diff --git a/third_party/blink/renderer/modules/BUILD.gn b/third_party/blink/renderer/modules/BUILD.gn
index d51e6eb..709f0516 100644
--- a/third_party/blink/renderer/modules/BUILD.gn
+++ b/third_party/blink/renderer/modules/BUILD.gn
@@ -1007,6 +1007,7 @@
     "//third_party/blink/renderer/core",
     "//third_party/blink/renderer/core:testing",
     "//third_party/blink/renderer/core:unit_test_support",
+    "//third_party/blink/renderer/modules/ad_auction:unit_tests",
     "//third_party/blink/renderer/modules/breakout_box:unit_tests",
     "//third_party/blink/renderer/modules/file_system_access:unit_tests",
     "//third_party/blink/renderer/modules/gamepad:unit_tests",
@@ -1015,6 +1016,7 @@
     "//third_party/blink/renderer/modules/indexeddb:unit_tests",
     "//third_party/blink/renderer/modules/mediarecorder:buildflags",
     "//third_party/blink/renderer/modules/mediastream:test_support",
+    "//third_party/blink/renderer/modules/ml:unit_tests",
     "//third_party/blink/renderer/modules/peerconnection:test_support",
     "//third_party/blink/renderer/modules/storage:unit_tests",
     "//third_party/blink/renderer/modules/webcodecs:unit_tests",
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
index 238a2d5..cbba4fbc 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
@@ -5388,7 +5388,6 @@
   }
 
   need_to_send_location_changes_ = true;
-  MarkElementDirty(document);
   DeferTreeUpdate(TreeUpdateReason::kMarkDirtyFromHandleLayout, document);
 }
 
@@ -5419,15 +5418,6 @@
 }
 
 void AXObjectCacheImpl::HandleScrollPositionChanged(
-    LocalFrameView* frame_view) {
-  SCOPED_DISALLOW_LIFECYCLE_TRANSITION();
-
-  InvalidateBoundingBoxForFixedOrStickyPosition();
-  need_to_send_location_changes_ = true;
-  MarkElementDirty(document_);
-}
-
-void AXObjectCacheImpl::HandleScrollPositionChanged(
     LayoutObject* layout_object) {
   SCOPED_DISALLOW_LIFECYCLE_TRANSITION();
   InvalidateBoundingBoxForFixedOrStickyPosition();
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
index 54a5b5a1..7774dd5 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
@@ -70,7 +70,6 @@
 class AXRelationCache;
 class AbstractInlineTextBox;
 class HTMLAreaElement;
-class LocalFrameView;
 class WebLocalFrameClient;
 
 // Describes a decicion on whether to create an AXNodeObject, an AXLayoutObject,
@@ -313,7 +312,6 @@
   void EmbeddingTokenChanged(HTMLFrameOwnerElement*) override;
 
   // Called when the scroll offset changes.
-  void HandleScrollPositionChanged(LocalFrameView*) override;
   void HandleScrollPositionChanged(LayoutObject*) override;
 
   void HandleScrolledToAnchor(const Node* anchor_node) override;
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_test.cc b/third_party/blink/renderer/modules/accessibility/ax_object_cache_test.cc
index c75c152a..36efc276 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_test.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_test.cc
@@ -241,8 +241,7 @@
   }
 
  protected:
-  test::TaskEnvironment task_environment_{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment_;
   std::unique_ptr<frame_test_helpers::WebViewHelper> web_view_helper_;
 };
 
diff --git a/third_party/blink/renderer/modules/ad_auction/BUILD.gn b/third_party/blink/renderer/modules/ad_auction/BUILD.gn
index b889c9f5..10c3d4df 100644
--- a/third_party/blink/renderer/modules/ad_auction/BUILD.gn
+++ b/third_party/blink/renderer/modules/ad_auction/BUILD.gn
@@ -33,6 +33,7 @@
     "//third_party/blink/public:test_headers",
     "//third_party/blink/public/common:headers",
     "//third_party/blink/renderer/modules:modules",
+    "//third_party/blink/renderer/platform:test_support",
     "//url",
   ]
 }
diff --git a/third_party/blink/renderer/modules/ad_auction/join_leave_queue_test.cc b/third_party/blink/renderer/modules/ad_auction/join_leave_queue_test.cc
index 1c28bafb..790286f27 100644
--- a/third_party/blink/renderer/modules/ad_auction/join_leave_queue_test.cc
+++ b/third_party/blink/renderer/modules/ad_auction/join_leave_queue_test.cc
@@ -10,6 +10,7 @@
 #include "base/functional/bind.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 
 namespace blink {
@@ -25,6 +26,7 @@
  protected:
   void Start(int&& i) { start_order_.push_back(i); }
 
+  test::TaskEnvironment task_environment_;
   std::unique_ptr<JoinLeaveQueue<int>> queue_;
 
   std::vector<int> start_order_;
diff --git a/third_party/blink/renderer/modules/ad_auction/validate_blink_interest_group_test.cc b/third_party/blink/renderer/modules/ad_auction/validate_blink_interest_group_test.cc
index 7219a095..e46f7eef 100644
--- a/third_party/blink/renderer/modules/ad_auction/validate_blink_interest_group_test.cc
+++ b/third_party/blink/renderer/modules/ad_auction/validate_blink_interest_group_test.cc
@@ -16,6 +16,7 @@
 #include "third_party/blink/public/mojom/interest_group/interest_group_types.mojom-blink.h"
 #include "third_party/blink/public/mojom/interest_group/interest_group_types.mojom.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -181,6 +182,7 @@
   const scoped_refptr<const SecurityOrigin> kAggregationCoordinatorOrigin =
       SecurityOrigin::CreateFromString(
           String::FromUTF8(kAggregationCoordinatorOriginString));
+  test::TaskEnvironment task_environment_;
 };
 
 // Test behavior with an InterestGroup with as few fields populated as allowed.
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
index 1a6f0a4..6e1110c1 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
@@ -209,8 +209,7 @@
     GetDocument().View()->UpdateAllLifecyclePhasesForTest();
   }
 
-  test::TaskEnvironment task_environment_{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment_;
   std::unique_ptr<frame_test_helpers::WebViewHelper> web_view_helper_;
   Persistent<HTMLCanvasElement> canvas_element_;
 
diff --git a/third_party/blink/renderer/modules/content_extraction/inner_html_builder_unittest.cc b/third_party/blink/renderer/modules/content_extraction/inner_html_builder_unittest.cc
index 64ee812..3972a33 100644
--- a/third_party/blink/renderer/modules/content_extraction/inner_html_builder_unittest.cc
+++ b/third_party/blink/renderer/modules/content_extraction/inner_html_builder_unittest.cc
@@ -14,8 +14,7 @@
 namespace {
 
 TEST(InnerHtmlBuilderTest, Basic) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   frame_test_helpers::WebViewHelper helper;
   helper.Initialize();
   ASSERT_TRUE(helper.LocalMainFrame());
diff --git a/third_party/blink/renderer/modules/content_extraction/inner_text_builder_unittest.cc b/third_party/blink/renderer/modules/content_extraction/inner_text_builder_unittest.cc
index 638ea1e..8b271029 100644
--- a/third_party/blink/renderer/modules/content_extraction/inner_text_builder_unittest.cc
+++ b/third_party/blink/renderer/modules/content_extraction/inner_text_builder_unittest.cc
@@ -29,8 +29,7 @@
 namespace {
 
 TEST(InnerTextBuilderTest, Basic) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   frame_test_helpers::WebViewHelper helper;
   helper.Initialize();
   // ScopedNullExecutionContext execution_context;
@@ -62,8 +61,7 @@
 }
 
 TEST(InnerTextBuilderTest, MultiFrames) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   frame_test_helpers::WebViewHelper helper;
   std::string base_url("http://internal.test/");
   url_test_helpers::RegisterMockedURLLoadFromBase(WebString::FromUTF8(base_url),
@@ -143,8 +141,7 @@
 }
 
 TEST(InnerTextBuilderTest, DifferentOrigin) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   frame_test_helpers::WebViewHelper helper;
   std::string base_url("http://internal.test/");
   url_test_helpers::RegisterMockedURLLoadFromBase(WebString::FromUTF8(base_url),
diff --git a/third_party/blink/renderer/modules/credentialmanagement/credentials_container_test.cc b/third_party/blink/renderer/modules/credentialmanagement/credentials_container_test.cc
index 2fea14d..dddee80 100644
--- a/third_party/blink/renderer/modules/credentialmanagement/credentials_container_test.cc
+++ b/third_party/blink/renderer/modules/credentialmanagement/credentials_container_test.cc
@@ -145,8 +145,7 @@
 // a persistent handle to a ScriptPromiseResolver instance. Ensure that if the
 // document is destroyed while a call is pending, it can still be freed up.
 TEST(CredentialsContainerTest, PendingGetRequest_NoGCCycles) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   MockCredentialManager mock_credential_manager;
   GCObjectLivenessObserver<Document> document_observer;
 
@@ -172,8 +171,7 @@
 // should be left unresolved, and there should be no crashes.
 TEST(CredentialsContainerTest,
      PendingGetRequest_NoCrashOnResponseAfterDocumentShutdown) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   MockCredentialManager mock_credential_manager;
   CredentialManagerTestingContext context(&mock_credential_manager);
 
@@ -191,8 +189,7 @@
 }
 
 TEST(CredentialsContainerTest, RejectPublicKeyCredentialStoreOperation) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   MockCredentialManager mock_credential_manager;
   CredentialManagerTestingContext context(&mock_credential_manager);
 
diff --git a/third_party/blink/renderer/modules/installedapp/installed_app_controller_test.cc b/third_party/blink/renderer/modules/installedapp/installed_app_controller_test.cc
index e974045..105b42c 100644
--- a/third_party/blink/renderer/modules/installedapp/installed_app_controller_test.cc
+++ b/third_party/blink/renderer/modules/installedapp/installed_app_controller_test.cc
@@ -64,8 +64,7 @@
   }
 
  private:
-  test::TaskEnvironment task_environment_{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment_;
   std::unique_ptr<DummyPageHolder> holder_;
   v8::HandleScope handle_scope_;
   v8::Local<v8::Context> context_;
diff --git a/third_party/blink/renderer/modules/media_capabilities/media_capabilities_test.cc b/third_party/blink/renderer/modules/media_capabilities/media_capabilities_test.cc
index df76d70e..6361c4e 100644
--- a/third_party/blink/renderer/modules/media_capabilities/media_capabilities_test.cc
+++ b/third_party/blink/renderer/modules/media_capabilities/media_capabilities_test.cc
@@ -1149,8 +1149,7 @@
 // Test that decodingInfo() behaves correctly for all orderings/timings of the
 // underlying prediction services.
 TEST(MediaCapabilitiesTests, PredictionCallbackPermutations) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   std::vector<PredictionType> callback_order(
       {PredictionType::kDB, PredictionType::kBadWindow, PredictionType::kNnr,
        PredictionType::kGpuFactories});
diff --git a/third_party/blink/renderer/modules/ml/ml_model_loader_test.cc b/third_party/blink/renderer/modules/ml/ml_model_loader_test.cc
index fd87fe45..64c0077 100644
--- a/third_party/blink/renderer/modules/ml/ml_model_loader_test.cc
+++ b/third_party/blink/renderer/modules/ml/ml_model_loader_test.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "third_party/blink/renderer/modules/ml/ml_model_loader.h"
+
 #include "components/ml/mojom/web_platform_model.mojom-blink.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -27,6 +28,7 @@
 #include "third_party/blink/renderer/modules/ml/ml_model_loader_test_util.h"
 #include "third_party/blink/renderer/platform/bindings/exception_code.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
@@ -185,6 +187,7 @@
   }
 
  protected:
+  test::TaskEnvironment task_environment_;
   FakeMLService service_;
   FakeMLModelLoader loader_;
   FakeMLModel model_;
diff --git a/third_party/blink/renderer/modules/ml/ml_trace_unittest.cc b/third_party/blink/renderer/modules/ml/ml_trace_unittest.cc
index a98e0a89..fb4fc214 100644
--- a/third_party/blink/renderer/modules/ml/ml_trace_unittest.cc
+++ b/third_party/blink/renderer/modules/ml/ml_trace_unittest.cc
@@ -20,6 +20,7 @@
 #include "base/trace_event/trace_log.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
 
 namespace blink {
@@ -95,6 +96,7 @@
   }
 
   // The task runner we use for posting tasks.
+  test::TaskEnvironment task_environment_;
   scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner_;
 };
 
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.cc
index 75e1dd8..8b19150 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.cc
@@ -23,6 +23,7 @@
 #include "third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.h"
 #include "third_party/blink/renderer/modules/ml/webnn/ml_operand.h"
 #include "third_party/blink/renderer/modules/ml/webnn/ml_operator.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
 
 namespace blink {
 
@@ -33,6 +34,7 @@
  public:
   MLGraphBuilderTest() = default;
   ~MLGraphBuilderTest() override = default;
+  test::TaskEnvironment task_environment_;
 };
 
 TEST_F(MLGraphBuilderTest, InputTest) {
@@ -3748,6 +3750,9 @@
                 "The input operand data types don't match.");
     }
   }
+
+ private:
+  test::TaskEnvironment task_environment_;
 };
 
 TEST_P(MLGraphBuilderElementWiseBinaryTest, TestElementWiseBinary) {
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.h b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.h
index 91a803c..b823c9b0 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.h
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.h
@@ -17,6 +17,7 @@
 #include "third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_utils.h"
 #include "third_party/blink/renderer/modules/ml/webnn/ml_operand.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
+#include "third_party/blink/renderer/platform/testing/task_environment.h"
 
 #if BUILDFLAG(BUILD_WEBNN_ON_CROS)
 #include "third_party/blink/renderer/modules/ml/webnn/ml_graph_test_cros.h"
@@ -84,6 +85,7 @@
  private:
   // The execution mode for testing build and compute graph (e.g. async, sync.).
   ExecutionMode GetExecutionMode();
+  test::TaskEnvironment task_environment_;
 };
 
 // This class performs backend specific setup.
diff --git a/third_party/blink/renderer/modules/notifications/notification_data_test.cc b/third_party/blink/renderer/modules/notifications/notification_data_test.cc
index 47a6546..89a64e1e 100644
--- a/third_party/blink/renderer/modules/notifications/notification_data_test.cc
+++ b/third_party/blink/renderer/modules/notifications/notification_data_test.cc
@@ -51,8 +51,7 @@
 const int kNotificationVibrationNormalized[] = {10, 10000, 50};
 
 TEST(NotificationDataTest, ReflectProperties) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   const KURL base_url(kNotificationBaseUrl);
   V8TestingScope scope(base_url);
 
@@ -144,8 +143,7 @@
 }
 
 TEST(NotificationDataTest, SilentNotificationWithVibration) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
 
   Vector<unsigned> vibration_pattern;
@@ -172,8 +170,7 @@
 }
 
 TEST(NotificationDataTest, ActionTypeButtonWithPlaceholder) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
 
   HeapVector<Member<NotificationAction>> actions;
@@ -197,8 +194,7 @@
 }
 
 TEST(NotificationDataTest, RenotifyWithEmptyTag) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
 
   NotificationOptions* options =
@@ -218,8 +214,7 @@
 }
 
 TEST(NotificationDataTest, InvalidIconUrls) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
 
   HeapVector<Member<NotificationAction>> actions;
@@ -252,8 +247,7 @@
 }
 
 TEST(NotificationDataTest, VibrationNormalization) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
 
   Vector<unsigned> unnormalized_pattern;
@@ -287,8 +281,7 @@
 }
 
 TEST(NotificationDataTest, DefaultTimestampValue) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
 
   NotificationOptions* options =
@@ -308,8 +301,7 @@
 }
 
 TEST(NotificationDataTest, DirectionValues) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
 
   WTF::HashMap<String, mojom::blink::NotificationDirection> mappings;
@@ -333,8 +325,7 @@
 }
 
 TEST(NotificationDataTest, MaximumActionCount) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
 
   HeapVector<Member<NotificationAction>> actions;
@@ -366,8 +357,7 @@
 }
 
 TEST(NotificationDataTest, RejectsTriggerTimestampOverAYear) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
 
   base::Time show_timestamp =
diff --git a/third_party/blink/renderer/modules/payments/abort_test.cc b/third_party/blink/renderer/modules/payments/abort_test.cc
index 3482072..ab8517d 100644
--- a/third_party/blink/renderer/modules/payments/abort_test.cc
+++ b/third_party/blink/renderer/modules/payments/abort_test.cc
@@ -20,8 +20,7 @@
 // If request.abort() is called without calling request.show() first, then
 // abort() should reject with exception.
 TEST(AbortTest, CannotAbortBeforeShow) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   PaymentRequest* request = PaymentRequest::Create(
       scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
@@ -35,8 +34,7 @@
 // If request.abort() is called again before the previous abort() resolved, then
 // the second abort() should reject with exception.
 TEST(AbortTest, CannotAbortTwiceConcurrently) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   PaymentRequest* request = PaymentRequest::Create(
       scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
@@ -56,8 +54,7 @@
 // If request.abort() is called after calling request.show(), then abort()
 // should not reject with exception.
 TEST(AbortTest, CanAbortAfterShow) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -75,8 +72,7 @@
 // If the browser is unable to abort the payment, then the request.abort()
 // promise should be rejected.
 TEST(AbortTest, FailedAbortShouldRejectAbortPromise) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -97,8 +93,7 @@
 // After the browser is unable to abort the payment once, the second abort()
 // call should not be rejected, as it's not a duplicate request anymore.
 TEST(AbortTest, CanAbortAgainAfterFirstAbortRejected) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -120,8 +115,7 @@
 // If the browser successfully aborts the payment, then the request.show()
 // promise should be rejected, and request.abort() promise should be resolved.
 TEST(AbortTest, SuccessfulAbortShouldRejectShowPromiseAndResolveAbortPromise) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
diff --git a/third_party/blink/renderer/modules/payments/can_make_payment_test.cc b/third_party/blink/renderer/modules/payments/can_make_payment_test.cc
index 77b9740..af00379 100644
--- a/third_party/blink/renderer/modules/payments/can_make_payment_test.cc
+++ b/third_party/blink/renderer/modules/payments/can_make_payment_test.cc
@@ -22,8 +22,7 @@
 using payments::mojom::blink::PaymentRequestClient;
 
 TEST(HasEnrolledInstrumentTest, RejectPromiseOnUserCancel) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -38,8 +37,7 @@
 }
 
 TEST(HasEnrolledInstrumentTest, RejectPromiseOnUnknownError) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -54,8 +52,7 @@
 }
 
 TEST(HasEnrolledInstrumentTest, RejectDuplicateRequest) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   PaymentRequest* request = PaymentRequest::Create(
       scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
@@ -68,8 +65,7 @@
 }
 
 TEST(HasEnrolledInstrumentTest, RejectQueryQuotaExceeded) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -84,8 +80,7 @@
 }
 
 TEST(HasEnrolledInstrumentTest, ReturnHasNoEnrolledInstrument) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -103,8 +98,7 @@
 }
 
 TEST(HasEnrolledInstrumentTest, ReturnHasEnrolledInstrument) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -122,8 +116,7 @@
 }
 
 TEST(CanMakePaymentTest, RejectPromiseOnUserCancel) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -138,8 +131,7 @@
 }
 
 TEST(CanMakePaymentTest, RejectPromiseOnUnknownError) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
 
   MockFunctionScope funcs(scope.GetScriptState());
@@ -155,8 +147,7 @@
 }
 
 TEST(CanMakePaymentTest, RejectDuplicateRequest) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   PaymentRequest* request = PaymentRequest::Create(
       scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
@@ -169,8 +160,7 @@
 }
 
 TEST(CanMakePaymentTest, ReturnCannotMakePayment) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -188,8 +178,7 @@
 }
 
 TEST(CanMakePaymentTest, ReturnCanMakePayment) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
diff --git a/third_party/blink/renderer/modules/payments/complete_test.cc b/third_party/blink/renderer/modules/payments/complete_test.cc
index 2c2d319..9bf74e5f 100644
--- a/third_party/blink/renderer/modules/payments/complete_test.cc
+++ b/third_party/blink/renderer/modules/payments/complete_test.cc
@@ -18,8 +18,7 @@
 namespace {
 
 TEST(CompleteTest, CannotCallCompleteTwice) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   PaymentRequest* request = PaymentRequest::Create(
       scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
@@ -42,8 +41,7 @@
 }
 
 TEST(CompleteTest, ResolveCompletePromiseOnUnknownError) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -67,8 +65,7 @@
 }
 
 TEST(CompleteTest, ResolveCompletePromiseOnUserClosingUI) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -95,8 +92,7 @@
 // If user cancels the transaction during processing, the complete() promise
 // should be rejected.
 TEST(CompleteTest, RejectCompletePromiseAfterError) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   PaymentRequest* request = PaymentRequest::Create(
       scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
@@ -119,8 +115,7 @@
 }
 
 TEST(CompleteTest, ResolvePromiseOnComplete) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -144,8 +139,7 @@
 }
 
 TEST(CompleteTest, RejectCompletePromiseOnUpdateDetailsFailure) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -173,8 +167,7 @@
 }
 
 TEST(CompleteTest, RejectCompletePromiseAfterTimeout) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
diff --git a/third_party/blink/renderer/modules/payments/on_payment_response_test.cc b/third_party/blink/renderer/modules/payments/on_payment_response_test.cc
index a76b477..211a79a 100644
--- a/third_party/blink/renderer/modules/payments/on_payment_response_test.cc
+++ b/third_party/blink/renderer/modules/payments/on_payment_response_test.cc
@@ -26,8 +26,7 @@
 // If the merchant requests shipping information, but the browser does not
 // provide the shipping option, reject the show() promise.
 TEST(OnPaymentResponseTest, RejectMissingShippingOption) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentOptions* options = PaymentOptions::Create();
@@ -52,8 +51,7 @@
 // If the merchant requests shipping information, but the browser does not
 // provide a shipping address, reject the show() promise.
 TEST(OnPaymentResponseTest, RejectMissingAddress) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentOptions* options = PaymentOptions::Create();
@@ -77,8 +75,7 @@
 // If the merchant requests a payer name, but the browser does not provide it,
 // reject the show() promise.
 TEST(OnPaymentResponseTest, RejectMissingName) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentOptions* options = PaymentOptions::Create();
@@ -101,8 +98,7 @@
 // If the merchant requests an email address, but the browser does not provide
 // it, reject the show() promise.
 TEST(OnPaymentResponseTest, RejectMissingEmail) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentOptions* options = PaymentOptions::Create();
@@ -125,8 +121,7 @@
 // If the merchant requests a phone number, but the browser does not provide it,
 // reject the show() promise.
 TEST(OnPaymentResponseTest, RejectMissingPhone) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentOptions* options = PaymentOptions::Create();
@@ -149,8 +144,7 @@
 // If the merchant requests shipping information, but the browser provides an
 // empty string for shipping option, reject the show() promise.
 TEST(OnPaymentResponseTest, RejectEmptyShippingOption) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentOptions* options = PaymentOptions::Create();
@@ -176,8 +170,7 @@
 // If the merchant requests shipping information, but the browser provides an
 // empty shipping address, reject the show() promise.
 TEST(OnPaymentResponseTest, RejectEmptyAddress) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentOptions* options = PaymentOptions::Create();
@@ -202,8 +195,7 @@
 // If the merchant requests a payer name, but the browser provides an empty
 // string for name, reject the show() promise.
 TEST(OnPaymentResponseTest, RejectEmptyName) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentOptions* options = PaymentOptions::Create();
@@ -227,8 +219,7 @@
 // If the merchant requests an email, but the browser provides an empty string
 // for email, reject the show() promise.
 TEST(OnPaymentResponseTest, RejectEmptyEmail) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentOptions* options = PaymentOptions::Create();
@@ -252,8 +243,7 @@
 // If the merchant requests a phone number, but the browser provides an empty
 // string for the phone number, reject the show() promise.
 TEST(OnPaymentResponseTest, RejectEmptyPhone) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentOptions* options = PaymentOptions::Create();
@@ -277,8 +267,7 @@
 // If the merchant does not request shipping information, but the browser
 // provides a shipping address, reject the show() promise.
 TEST(OnPaymentResponseTest, RejectNotRequestedAddress) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentOptions* options = PaymentOptions::Create();
@@ -303,8 +292,7 @@
 // If the merchant does not request shipping information, but the browser
 // provides a shipping option, reject the show() promise.
 TEST(OnPaymentResponseTest, RejectNotRequestedShippingOption) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentOptions* options = PaymentOptions::Create();
@@ -328,8 +316,7 @@
 // If the merchant does not request a payer name, but the browser provides it,
 // reject the show() promise.
 TEST(OnPaymentResponseTest, RejectNotRequestedName) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentOptions* options = PaymentOptions::Create();
@@ -353,8 +340,7 @@
 // If the merchant does not request an email, but the browser provides it,
 // reject the show() promise.
 TEST(OnPaymentResponseTest, RejectNotRequestedEmail) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentOptions* options = PaymentOptions::Create();
@@ -378,8 +364,7 @@
 // If the merchant does not request a phone number, but the browser provides it,
 // reject the show() promise.
 TEST(OnPaymentResponseTest, RejectNotRequestedPhone) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentOptions* options = PaymentOptions::Create();
@@ -403,8 +388,7 @@
 // If the merchant requests shipping information, but the browser provides an
 // invalid shipping address, reject the show() promise.
 TEST(OnPaymentResponseTest, RejectInvalidAddress) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentOptions* options = PaymentOptions::Create();
@@ -446,8 +430,7 @@
 // If the merchant requests shipping information, the resolved show() promise
 // should contain a shipping option and an address.
 TEST(OnPaymentResponseTest, CanRequestShippingInformation) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentOptions* options = PaymentOptions::Create();
@@ -483,8 +466,7 @@
 // If the merchant requests a payer name, the resolved show() promise should
 // contain a payer name.
 TEST(OnPaymentResponseTest, CanRequestName) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentOptions* options = PaymentOptions::Create();
@@ -519,8 +501,7 @@
 // If the merchant requests an email address, the resolved show() promise should
 // contain an email address.
 TEST(OnPaymentResponseTest, CanRequestEmail) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentOptions* options = PaymentOptions::Create();
@@ -554,8 +535,7 @@
 // If the merchant requests a phone number, the resolved show() promise should
 // contain a phone number.
 TEST(OnPaymentResponseTest, CanRequestPhone) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentOptions* options = PaymentOptions::Create();
@@ -589,8 +569,7 @@
 // If the merchant does not request shipping information, the resolved show()
 // promise should contain null shipping option and address.
 TEST(OnPaymentResponseTest, ShippingInformationNotRequired) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentOptions* options = PaymentOptions::Create();
@@ -622,8 +601,7 @@
 // If the merchant does not request a phone number, the resolved show() promise
 // should contain null phone number.
 TEST(OnPaymentResponseTest, PhoneNotRequired) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentOptions* options = PaymentOptions::Create();
@@ -657,8 +635,7 @@
 // If the merchant does not request a payer name, the resolved show() promise
 // should contain null payer name.
 TEST(OnPaymentResponseTest, NameNotRequired) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentOptions* options = PaymentOptions::Create();
@@ -692,8 +669,7 @@
 // If the merchant does not request an email address, the resolved show()
 // promise should contain null email address.
 TEST(OnPaymentResponseTest, EmailNotRequired) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentOptions* options = PaymentOptions::Create();
diff --git a/third_party/blink/renderer/modules/payments/payment_request_details_test.cc b/third_party/blink/renderer/modules/payments/payment_request_details_test.cc
index 0d5e8fb..11ddca5 100644
--- a/third_party/blink/renderer/modules/payments/payment_request_details_test.cc
+++ b/third_party/blink/renderer/modules/payments/payment_request_details_test.cc
@@ -126,8 +126,7 @@
 class PaymentRequestDetailsTest
     : public testing::TestWithParam<DetailsTestCase> {
  protected:
-  test::TaskEnvironment task_environment_{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment_;
 };
 
 TEST_P(PaymentRequestDetailsTest, ValidatesDetails) {
diff --git a/third_party/blink/renderer/modules/payments/payment_request_for_invalid_origin_or_ssl_test.cc b/third_party/blink/renderer/modules/payments/payment_request_for_invalid_origin_or_ssl_test.cc
index 33b0ec8..133cb9f 100644
--- a/third_party/blink/renderer/modules/payments/payment_request_for_invalid_origin_or_ssl_test.cc
+++ b/third_party/blink/renderer/modules/payments/payment_request_for_invalid_origin_or_ssl_test.cc
@@ -101,8 +101,7 @@
         payment_provider_->CreatePendingRemoteAndBind(), ASSERT_NO_EXCEPTION);
   }
 
-  test::TaskEnvironment task_environment_{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment_;
   std::unique_ptr<MockPaymentProvider> payment_provider_;
   ScopedTestingPlatformSupport<TestingPlatformSupport> platform_;
 };
diff --git a/third_party/blink/renderer/modules/payments/payment_request_optional_total_test.cc b/third_party/blink/renderer/modules/payments/payment_request_optional_total_test.cc
index 2cf56ffb..48de5008 100644
--- a/third_party/blink/renderer/modules/payments/payment_request_optional_total_test.cc
+++ b/third_party/blink/renderer/modules/payments/payment_request_optional_total_test.cc
@@ -70,8 +70,7 @@
     payment_provider_ = std::make_unique<MockPaymentProvider>();
   }
 
-  test::TaskEnvironment task_environment_{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment_;
   std::unique_ptr<MockPaymentProvider> payment_provider_;
   ScopedTestingPlatformSupport<TestingPlatformSupport> platform_;
 };
diff --git a/third_party/blink/renderer/modules/payments/payment_request_test.cc b/third_party/blink/renderer/modules/payments/payment_request_test.cc
index 68321f9..12fe9b72 100644
--- a/third_party/blink/renderer/modules/payments/payment_request_test.cc
+++ b/third_party/blink/renderer/modules/payments/payment_request_test.cc
@@ -27,8 +27,7 @@
 namespace {
 
 TEST(PaymentRequestTest, NoExceptionWithValidData) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   PaymentRequest::Create(
       scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
@@ -38,8 +37,7 @@
 }
 
 TEST(PaymentRequestTest, SupportedMethodListRequired) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   PaymentRequest::Create(
       scope.GetExecutionContext(), HeapVector<Member<PaymentMethodData>>(),
@@ -51,8 +49,7 @@
 }
 
 TEST(PaymentRequestTest, NullShippingOptionWhenNoOptionsAvailable) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   PaymentDetailsInit* details = PaymentDetailsInit::Create();
   details->setTotal(BuildPaymentItemForTest());
@@ -67,8 +64,7 @@
 }
 
 TEST(PaymentRequestTest, NullShippingOptionWhenMultipleOptionsAvailable) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   PaymentDetailsInit* details = PaymentDetailsInit::Create();
   details->setTotal(BuildPaymentItemForTest());
@@ -87,8 +83,7 @@
 }
 
 TEST(PaymentRequestTest, DontSelectSingleAvailableShippingOptionByDefault) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   PaymentDetailsInit* details = PaymentDetailsInit::Create();
   details->setTotal(BuildPaymentItemForTest());
@@ -105,8 +100,7 @@
 
 TEST(PaymentRequestTest,
      DontSelectSingleAvailableShippingOptionWhenShippingNotRequested) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   PaymentDetailsInit* details = PaymentDetailsInit::Create();
   details->setTotal(BuildPaymentItemForTest());
@@ -124,8 +118,7 @@
 
 TEST(PaymentRequestTest,
      DontSelectSingleUnselectedShippingOptionWhenShippingRequested) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   PaymentDetailsInit* details = PaymentDetailsInit::Create();
   details->setTotal(BuildPaymentItemForTest());
@@ -143,8 +136,7 @@
 
 TEST(PaymentRequestTest,
      SelectSingleSelectedShippingOptionWhenShippingRequested) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   PaymentDetailsInit* details = PaymentDetailsInit::Create();
   details->setTotal(BuildPaymentItemForTest());
@@ -165,8 +157,7 @@
 
 TEST(PaymentRequestTest,
      SelectOnlySelectedShippingOptionWhenShippingRequested) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   PaymentDetailsInit* details = PaymentDetailsInit::Create();
   details->setTotal(BuildPaymentItemForTest());
@@ -189,8 +180,7 @@
 
 TEST(PaymentRequestTest,
      SelectLastSelectedShippingOptionWhenShippingRequested) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   PaymentDetailsInit* details = PaymentDetailsInit::Create();
   details->setTotal(BuildPaymentItemForTest());
@@ -213,8 +203,7 @@
 }
 
 TEST(PaymentRequestTest, NullShippingTypeWhenRequestShippingIsFalse) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   PaymentDetailsInit* details = PaymentDetailsInit::Create();
   details->setTotal(BuildPaymentItemForTest());
@@ -230,8 +219,7 @@
 
 TEST(PaymentRequestTest,
      DefaultShippingTypeWhenRequestShippingIsTrueWithNoSpecificType) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   PaymentDetailsInit* details = PaymentDetailsInit::Create();
   details->setTotal(BuildPaymentItemForTest());
@@ -246,8 +234,7 @@
 }
 
 TEST(PaymentRequestTest, DeliveryShippingTypeWhenShippingTypeIsDelivery) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   PaymentDetailsInit* details = PaymentDetailsInit::Create();
   details->setTotal(BuildPaymentItemForTest());
@@ -263,8 +250,7 @@
 }
 
 TEST(PaymentRequestTest, PickupShippingTypeWhenShippingTypeIsPickup) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   PaymentDetailsInit* details = PaymentDetailsInit::Create();
   details->setTotal(BuildPaymentItemForTest());
@@ -280,8 +266,7 @@
 }
 
 TEST(PaymentRequestTest, RejectShowPromiseOnInvalidShippingAddress) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -298,8 +283,7 @@
 }
 
 TEST(PaymentRequestTest, OnShippingOptionChange) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -316,8 +300,7 @@
 }
 
 TEST(PaymentRequestTest, CannotCallShowTwice) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -335,8 +318,7 @@
 }
 
 TEST(PaymentRequestTest, CannotShowAfterAborted) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -359,8 +341,7 @@
 }
 
 TEST(PaymentRequestTest, CannotShowWithoutUserActivation) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   ScopedPaymentRequestAllowOneActivationlessShowForTest
       scoped_activationless_show_enabled(false);
   PaymentRequestV8TestingScope scope;
@@ -381,8 +362,7 @@
 }
 
 TEST(PaymentRequestTest, ShowConsumesUserActivation) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   ScopedPaymentRequestAllowOneActivationlessShowForTest
       scoped_activationless_show_enabled(false);
   PaymentRequestV8TestingScope scope;
@@ -401,8 +381,7 @@
 }
 
 TEST(PaymentRequestTest, PaymentRequestActivationlessShowEnabled) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   ScopedPaymentRequestAllowOneActivationlessShowForTest
       scoped_activationless_show_enabled(true);
   PaymentRequestV8TestingScope scope;
@@ -426,8 +405,7 @@
 }
 
 TEST(PaymentRequestTest, RejectShowPromiseOnErrorPaymentMethodNotSupported) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -450,8 +428,7 @@
 }
 
 TEST(PaymentRequestTest, RejectShowPromiseOnErrorCancelled) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -473,8 +450,7 @@
 }
 
 TEST(PaymentRequestTest, RejectShowPromiseOnUpdateDetailsFailure) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -496,8 +472,7 @@
 }
 
 TEST(PaymentRequestTest, IgnoreUpdatePaymentDetailsAfterShowPromiseResolved) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -516,8 +491,7 @@
 }
 
 TEST(PaymentRequestTest, RejectShowPromiseOnNonPaymentDetailsUpdate) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -536,8 +510,7 @@
 }
 
 TEST(PaymentRequestTest, RejectShowPromiseOnInvalidPaymentDetailsUpdate) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -560,8 +533,7 @@
 
 TEST(PaymentRequestTest,
      ClearShippingOptionOnPaymentDetailsUpdateWithoutShippingOptions) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentDetailsInit* details = PaymentDetailsInit::Create();
@@ -610,8 +582,7 @@
 TEST(
     PaymentRequestTest,
     ClearShippingOptionOnPaymentDetailsUpdateWithMultipleUnselectedShippingOptions) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentOptions* options = PaymentOptions::Create();
@@ -642,8 +613,7 @@
 }
 
 TEST(PaymentRequestTest, UseTheSelectedShippingOptionFromPaymentDetailsUpdate) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentOptions* options = PaymentOptions::Create();
@@ -676,8 +646,7 @@
 }
 
 TEST(PaymentRequestTest, NoExceptionWithErrorMessageInUpdate) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -702,8 +671,7 @@
 
 TEST(PaymentRequestTest,
      ShouldResolveWithExceptionIfIDsOfShippingOptionsAreDuplicated) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentDetailsInit* details = PaymentDetailsInit::Create();
@@ -724,8 +692,7 @@
 }
 
 TEST(PaymentRequestTest, DetailsIdIsSet) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   PaymentDetailsInit* details = PaymentDetailsInit::Create();
   details->setTotal(BuildPaymentItemForTest());
@@ -756,8 +723,7 @@
 };
 
 TEST(PaymentRequestTest, NoCrashWhenPaymentMethodChangeEventDestroysContext) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PageDeleter* page_deleter = MakeGarbageCollected<PageDeleter>();
   LocalFrame& frame = page_deleter->page()->GetFrame();
   auto* isolate = ToIsolate(&frame);
@@ -786,8 +752,7 @@
 }
 
 TEST(PaymentRequestTest, SPCActivationlessShowEnabled) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   ScopedSecurePaymentConfirmationAllowOneActivationlessShowForTest
       scoped_activationless_show_enabled(true);
 
@@ -815,8 +780,7 @@
 }
 
 TEST(PaymentRequestTest, SPCActivationlessShowDisabled) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   ScopedSecurePaymentConfirmationAllowOneActivationlessShowForTest
       scoped_activationless_show_enabled(false);
 
@@ -841,8 +805,7 @@
 }
 
 TEST(PaymentRequestTest, SPCActivationlessNotConsumedWithActivation) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   ScopedSecurePaymentConfirmationAllowOneActivationlessShowForTest
       scoped_activationless_show_enabled(true);
 
diff --git a/third_party/blink/renderer/modules/payments/payment_request_update_event_test.cc b/third_party/blink/renderer/modules/payments/payment_request_update_event_test.cc
index f9225909..857b0aa 100644
--- a/third_party/blink/renderer/modules/payments/payment_request_update_event_test.cc
+++ b/third_party/blink/renderer/modules/payments/payment_request_update_event_test.cc
@@ -43,8 +43,7 @@
 };
 
 TEST(PaymentRequestUpdateEventTest, OnUpdatePaymentDetailsCalled) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   PaymentRequestUpdateEvent* event = PaymentRequestUpdateEvent::Create(
       scope.GetExecutionContext(), event_type_names::kShippingaddresschange);
@@ -65,8 +64,7 @@
 }
 
 TEST(PaymentRequestUpdateEventTest, OnUpdatePaymentDetailsFailureCalled) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   PaymentRequestUpdateEvent* event = PaymentRequestUpdateEvent::Create(
       scope.GetExecutionContext(), event_type_names::kShippingaddresschange);
@@ -87,8 +85,7 @@
 }
 
 TEST(PaymentRequestUpdateEventTest, CannotUpdateWithoutDispatching) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   PaymentRequestUpdateEvent* event = PaymentRequestUpdateEvent::Create(
       scope.GetExecutionContext(), event_type_names::kShippingaddresschange);
@@ -104,8 +101,7 @@
 }
 
 TEST(PaymentRequestUpdateEventTest, CannotUpdateTwice) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   PaymentRequestUpdateEvent* event = PaymentRequestUpdateEvent::Create(
       scope.GetExecutionContext(), event_type_names::kShippingaddresschange);
@@ -130,8 +126,7 @@
 }
 
 TEST(PaymentRequestUpdateEventTest, UpdaterNotRequired) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   PaymentRequestUpdateEvent* event = PaymentRequestUpdateEvent::Create(
       scope.GetExecutionContext(), event_type_names::kShippingaddresschange);
@@ -147,8 +142,7 @@
 }
 
 TEST(PaymentRequestUpdateEventTest, AddressChangeUpdateWithTimeout) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -188,8 +182,7 @@
 }
 
 TEST(PaymentRequestUpdateEventTest, OptionChangeUpdateWithTimeout) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -229,8 +222,7 @@
 }
 
 TEST(PaymentRequestUpdateEventTest, AddressChangePromiseTimeout) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -268,8 +260,7 @@
 }
 
 TEST(PaymentRequestUpdateEventTest, OptionChangePromiseTimeout) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   PaymentRequestV8TestingScope scope;
   MockFunctionScope funcs(scope.GetScriptState());
   PaymentRequest* request = PaymentRequest::Create(
@@ -307,8 +298,7 @@
 }
 
 TEST(PaymentRequestUpdateEventTest, NotAllowUntrustedEvent) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   PaymentRequestUpdateEvent* event = PaymentRequestUpdateEvent::Create(
       scope.GetExecutionContext(), event_type_names::kShippingaddresschange);
diff --git a/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory_test.cc b/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory_test.cc
index 378b2dc..c62ee0b 100644
--- a/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory_test.cc
+++ b/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory_test.cc
@@ -44,8 +44,7 @@
   }
 
  protected:
-  test::TaskEnvironment task_environment_{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment_;
   Persistent<PeerConnectionDependencyFactory> dependency_factory_;
   Persistent<MockRTCPeerConnectionHandlerClient> mock_client_;
 };
diff --git a/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc b/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc
index f8073d5a..18a2f23 100644
--- a/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc
+++ b/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc
@@ -637,21 +637,32 @@
     scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner,
     base::PassKey<PeerConnectionTracker>)
     : Supplement<LocalDOMWindow>(window),
+      // Do not set a lifecycle notifier for `peer_connection_tracker_host_` to
+      // ensure that its mojo pipe stays alive until the execution context is
+      // destroyed. `RTCPeerConnection` (which owns a `RTCPeerConnectionHandler`
+      // which persistently kepts `this` alive) will attempt to close and
+      // unregister the peer connection when the execution context is destroyed,
+      // for which this mojo pipe _must_ be alive to relay.
+      // See https://crbug.com/1426377 for details.
+      peer_connection_tracker_host_(nullptr),
       receiver_(this, &window),
       main_thread_task_runner_(std::move(main_thread_task_runner)) {
   window.GetBrowserInterfaceBroker().GetInterface(
-      peer_connection_tracker_host_.BindNewPipeAndPassReceiver());
+      peer_connection_tracker_host_.BindNewPipeAndPassReceiver(
+          main_thread_task_runner_));
 }
 
 // Constructor used for testing. Note that receiver_ doesn't have a context
 // notifier in this case.
 PeerConnectionTracker::PeerConnectionTracker(
-    mojo::Remote<blink::mojom::blink::PeerConnectionTrackerHost> host,
+    mojo::PendingRemote<blink::mojom::blink::PeerConnectionTrackerHost> host,
     scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner)
     : Supplement(nullptr),
-      peer_connection_tracker_host_(std::move(host)),
+      peer_connection_tracker_host_(nullptr),
       receiver_(this, nullptr),
-      main_thread_task_runner_(std::move(main_thread_task_runner)) {}
+      main_thread_task_runner_(std::move(main_thread_task_runner)) {
+  peer_connection_tracker_host_.Bind(std::move(host), main_thread_task_runner_);
+}
 
 PeerConnectionTracker::~PeerConnectionTracker() {}
 
diff --git a/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.h b/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.h
index c87bc757..1bc68c2 100644
--- a/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.h
+++ b/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.h
@@ -10,18 +10,18 @@
 #include "base/threading/thread_checker.h"
 #include "base/types/pass_key.h"
 #include "base/values.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
-#include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/mojom/peerconnection/peer_connection_tracker.mojom-blink.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/modules/mediastream/media_stream.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
 #include "third_party/blink/renderer/platform/peerconnection/rtc_peer_connection_handler_client.h"
 #include "third_party/blink/renderer/platform/peerconnection/rtc_rtp_transceiver_platform.h"
 #include "third_party/blink/renderer/platform/peerconnection/rtc_session_description_platform.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
-#include "third_party/blink/renderer/platform/wtf/gc_plugin.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/webrtc/api/peer_connection_interface.h"
@@ -66,12 +66,12 @@
 
   // Ctors for tests.
   PeerConnectionTracker(
-      mojo::Remote<mojom::blink::PeerConnectionTrackerHost> host,
+      mojo::PendingRemote<mojom::blink::PeerConnectionTrackerHost> host,
       scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner,
       base::PassKey<PeerConnectionTrackerTest> key)
       : PeerConnectionTracker(std::move(host), main_thread_task_runner) {}
   PeerConnectionTracker(
-      mojo::Remote<mojom::blink::PeerConnectionTrackerHost> host,
+      mojo::PendingRemote<mojom::blink::PeerConnectionTrackerHost> host,
       scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner,
       base::PassKey<MockPeerConnectionTracker> key)
       : PeerConnectionTracker(std::move(host), main_thread_task_runner) {}
@@ -238,6 +238,7 @@
                                      const WTF::Vector<uint8_t>& output);
 
   void Trace(Visitor* visitor) const override {
+    visitor->Trace(peer_connection_tracker_host_);
     visitor->Trace(receiver_);
     Supplement<LocalDOMWindow>::Trace(visitor);
   }
@@ -250,7 +251,7 @@
                            ReportInitialThermalState);
 
   PeerConnectionTracker(
-      mojo::Remote<mojom::blink::PeerConnectionTrackerHost> host,
+      mojo::PendingRemote<mojom::blink::PeerConnectionTrackerHost> host,
       scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner);
 
   void Bind(mojo::PendingReceiver<blink::mojom::blink::PeerConnectionManager>
@@ -308,8 +309,7 @@
   int32_t current_speed_limit_ = mojom::blink::kSpeedLimitMax;
 
   THREAD_CHECKER(main_thread_);
-  GC_PLUGIN_IGNORE("https://crbug.com/1381979")
-  mojo::Remote<blink::mojom::blink::PeerConnectionTrackerHost>
+  HeapMojoRemote<blink::mojom::blink::PeerConnectionTrackerHost>
       peer_connection_tracker_host_;
   HeapMojoReceiver<blink::mojom::blink::PeerConnectionManager,
                    PeerConnectionTracker>
diff --git a/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker_test.cc b/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker_test.cc
index acd4b6e6..b67c555 100644
--- a/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker_test.cc
+++ b/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker_test.cc
@@ -68,12 +68,11 @@
   MOCK_METHOD2(AddStandardStats, void(int, base::Value::List));
   MOCK_METHOD2(AddLegacyStats, void(int, base::Value::List));
 
-  mojo::Remote<blink::mojom::blink::PeerConnectionTrackerHost>
+  mojo::PendingRemote<blink::mojom::blink::PeerConnectionTrackerHost>
   CreatePendingRemoteAndBind() {
     receiver_.reset();
-    return mojo::Remote<blink::mojom::blink::PeerConnectionTrackerHost>(
-        receiver_.BindNewPipeAndPassRemote(
-            blink::scheduler::GetSingleThreadTaskRunnerForTesting()));
+    return receiver_.BindNewPipeAndPassRemote(
+        blink::scheduler::GetSingleThreadTaskRunnerForTesting());
   }
 
   mojo::Receiver<blink::mojom::blink::PeerConnectionTrackerHost> receiver_{
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_data_channel_test.cc b/third_party/blink/renderer/modules/peerconnection/rtc_data_channel_test.cc
index 2690a40..a643a7cb 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_data_channel_test.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_data_channel_test.cc
@@ -257,8 +257,7 @@
   }
 
  protected:
-  test::TaskEnvironment task_environment_{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment_;
   Persistent<NullExecutionContext> execution_context_ =
       MakeGarbageCollected<NullExecutionContext>();
 
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.h b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.h
index c195b41..d92bf79 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.h
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.h
@@ -416,7 +416,8 @@
   // detect any removals during rollback.
   Vector<uintptr_t> previous_transceiver_ids_;
 
-  WeakPersistent<PeerConnectionTracker> peer_connection_tracker_;
+  // Keep persistently alive to ensure the peer connection will be unregistered.
+  Persistent<PeerConnectionTracker> peer_connection_tracker_;
 
   MediaStreamTrackMetrics track_metrics_;
 
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler_test.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler_test.cc
index bbbed46..7f97252a 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler_test.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler_test.cc
@@ -26,6 +26,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/platform/modules/mediastream/web_media_stream_track.h"
@@ -91,7 +92,7 @@
  public:
   MockPeerConnectionTracker()
       : PeerConnectionTracker(
-            mojo::Remote<mojom::blink::PeerConnectionTrackerHost>(),
+            mojo::PendingRemote<mojom::blink::PeerConnectionTrackerHost>(),
             blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
             base::PassKey<MockPeerConnectionTracker>()) {}
 
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc
index d30d6b7f..cbdc59d 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc
@@ -120,8 +120,7 @@
   }
 
  protected:
-  test::TaskEnvironment task_environment_{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment_;
   ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform_;
 };
 
diff --git a/third_party/blink/renderer/modules/presentation/presentation_request_test.cc b/third_party/blink/renderer/modules/presentation/presentation_request_test.cc
index 898befa..c368c87 100644
--- a/third_party/blink/renderer/modules/presentation/presentation_request_test.cc
+++ b/third_party/blink/renderer/modules/presentation/presentation_request_test.cc
@@ -45,8 +45,7 @@
 }
 
 TEST(PresentationRequestTest, TestSingleUrlConstructor) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   PresentationRequest* request = PresentationRequest::Create(
       scope.GetExecutionContext(), "https://example.com",
@@ -60,8 +59,7 @@
 }
 
 TEST(PresentationRequestTest, TestMultipleUrlConstructor) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   HeapVector<Member<V8UnionPresentationSourceOrUSVString>> sources =
       CreateUrlSources({"https://example.com", "cast://deadbeef?param=foo"});
@@ -79,8 +77,7 @@
 }
 
 TEST(PresentationRequestTest, TestMultipleUrlConstructorInvalidUrl) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   HeapVector<Member<V8UnionPresentationSourceOrUSVString>> sources =
       CreateUrlSources({"https://example.com", ""});
@@ -93,8 +90,7 @@
 }
 
 TEST(PresentationRequestTest, TestMixedContentNotCheckedForNonHttpFamily) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope(KURL("https://example.test"));
 
   PresentationRequest* request = PresentationRequest::Create(
@@ -109,8 +105,7 @@
 }
 
 TEST(PresentationRequestTest, TestSingleUrlConstructorMixedContent) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope(KURL("https://example.test"));
 
   PresentationRequest::Create(scope.GetExecutionContext(), "http://example.com",
@@ -121,8 +116,7 @@
 }
 
 TEST(PresentationRequestTest, TestMultipleUrlConstructorMixedContent) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope(KURL("https://example.test"));
 
   HeapVector<Member<V8UnionPresentationSourceOrUSVString>> sources =
@@ -136,8 +130,7 @@
 }
 
 TEST(PresentationRequestTest, TestMultipleUrlConstructorEmptySequence) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   HeapVector<Member<V8UnionPresentationSourceOrUSVString>> sources;
 
@@ -149,8 +142,7 @@
 }
 
 TEST(PresentationRequestTest, TestSingleUrlConstructorUnknownScheme) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   PresentationRequest::Create(scope.GetExecutionContext(), "foobar:unknown",
                               scope.GetExceptionState());
@@ -160,8 +152,7 @@
 }
 
 TEST(PresentationRequestTest, TestMultipleUrlConstructorSomeUnknownSchemes) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   HeapVector<Member<V8UnionPresentationSourceOrUSVString>> sources =
       CreateUrlSources({"foobar:unknown", "https://example.com",
@@ -180,8 +171,7 @@
 }
 
 TEST(PresentationRequestTest, TestMultipleUrlConstructorAllUnknownSchemes) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   HeapVector<Member<V8UnionPresentationSourceOrUSVString>> sources =
       CreateUrlSources({"foobar:unknown", "deadbeef:random"});
@@ -197,8 +187,7 @@
 // the PresentationSource specialization of V8UnionPresentationSourceOrUSVString
 // to be used to create a PresentationRequest.
 TEST(PresentationRequestTest, TestPresentationSourceNotAllowed) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   ScopedSiteInitiatedMirroringForTest site_initiated_mirroring_enabled{false};
   V8TestingScope scope;
   PresentationRequest::Create(scope.GetExecutionContext(),
@@ -210,8 +199,7 @@
 }
 
 TEST(PresentationRequestTest, TestPresentationSourcesInConstructor) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   ScopedSiteInitiatedMirroringForTest site_initiated_mirroring_enabled{true};
   V8TestingScope scope;
   PresentationRequest* request = PresentationRequest::Create(
@@ -234,8 +222,7 @@
 }
 
 TEST(PresentationRequestTest, TestInvalidPresentationSource) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   ScopedSiteInitiatedMirroringForTest site_initiated_mirroring_enabled{true};
   V8TestingScope scope;
   PresentationRequest::Create(scope.GetExecutionContext(),
diff --git a/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel_test.cc b/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel_test.cc
index 52a400a0e..7d991ea1 100644
--- a/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel_test.cc
+++ b/third_party/blink/renderer/modules/wake_lock/wake_lock_sentinel_test.cc
@@ -41,8 +41,7 @@
 }  // namespace
 
 TEST(WakeLockSentinelTest, SentinelType) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   MockWakeLockService wake_lock_service;
   WakeLockTestingContext context(&wake_lock_service);
 
@@ -58,8 +57,7 @@
 }
 
 TEST(WakeLockSentinelTest, SentinelReleased) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   MockWakeLockService wake_lock_service;
   WakeLockTestingContext context(&wake_lock_service);
 
@@ -77,8 +75,7 @@
 }
 
 TEST(WakeLockSentinelTest, MultipleReleaseCalls) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   MockWakeLockService wake_lock_service;
   WakeLockTestingContext context(&wake_lock_service);
 
@@ -116,8 +113,7 @@
 }
 
 TEST(WakeLockSentinelTest, ContextDestruction) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   MockWakeLockService wake_lock_service;
   WakeLockTestingContext context(&wake_lock_service);
 
@@ -154,8 +150,7 @@
 }
 
 TEST(WakeLockSentinelTest, HasPendingActivityConditions) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   MockWakeLockService wake_lock_service;
   WakeLockTestingContext context(&wake_lock_service);
 
diff --git a/third_party/blink/renderer/modules/wake_lock/wake_lock_test.cc b/third_party/blink/renderer/modules/wake_lock/wake_lock_test.cc
index 3ceff84..75477112 100644
--- a/third_party/blink/renderer/modules/wake_lock/wake_lock_test.cc
+++ b/third_party/blink/renderer/modules/wake_lock/wake_lock_test.cc
@@ -20,8 +20,7 @@
 namespace blink {
 
 TEST(WakeLockTest, RequestWakeLockGranted) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   MockWakeLockService wake_lock_service;
   WakeLockTestingContext context(&wake_lock_service);
 
@@ -49,8 +48,7 @@
 }
 
 TEST(WakeLockTest, RequestWakeLockDenied) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   MockWakeLockService wake_lock_service;
   WakeLockTestingContext context(&wake_lock_service);
 
@@ -85,8 +83,7 @@
 
 // https://w3c.github.io/screen-wake-lock/#handling-document-loss-of-full-activity
 TEST(WakeLockTest, LossOfDocumentActivity) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   MockWakeLockService wake_lock_service;
   WakeLockTestingContext context(&wake_lock_service);
 
@@ -131,8 +128,7 @@
 
 // https://w3c.github.io/screen-wake-lock/#handling-document-loss-of-visibility
 TEST(WakeLockTest, PageVisibilityHidden) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   MockWakeLockService wake_lock_service;
   WakeLockTestingContext context(&wake_lock_service);
 
@@ -184,8 +180,7 @@
 
 // https://w3c.github.io/screen-wake-lock/#handling-document-loss-of-visibility
 TEST(WakeLockTest, PageVisibilityHiddenBeforeLockAcquisition) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
 
   MockWakeLockService wake_lock_service;
   WakeLockTestingContext context(&wake_lock_service);
diff --git a/third_party/blink/renderer/modules/webaudio/audio_context_autoplay_test.cc b/third_party/blink/renderer/modules/webaudio/audio_context_autoplay_test.cc
index 08ba5caf..bcb06a2 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_context_autoplay_test.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_context_autoplay_test.cc
@@ -125,8 +125,7 @@
   }
 
  private:
-  test::TaskEnvironment task_environment_{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment_;
   ScopedTestingPlatformSupport<AudioContextAutoplayTestPlatform> platform_;
   frame_test_helpers::WebViewHelper helper_;
   std::unique_ptr<base::HistogramTester> histogram_tester_;
diff --git a/third_party/blink/renderer/modules/webdatabase/dom_window_web_database_test.cc b/third_party/blink/renderer/modules/webdatabase/dom_window_web_database_test.cc
index 37a0366..6a367aceb 100644
--- a/third_party/blink/renderer/modules/webdatabase/dom_window_web_database_test.cc
+++ b/third_party/blink/renderer/modules/webdatabase/dom_window_web_database_test.cc
@@ -66,8 +66,7 @@
 }
 
 TEST(DOMWindowWebDatabaseTest, WebSQLThirdPartyContext) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   OpenWebDatabaseInIFrame("http://not-example.test:0/",
                           "first_party/nested-originA.html",
@@ -80,8 +79,7 @@
 }
 
 TEST(DOMWindowWebDatabaseTest, WebSQLNonSecureContext) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   OpenWebDatabaseInWindow("http://example.test:0/", "first_party/empty.html",
                           scope.GetExceptionState());
@@ -93,8 +91,7 @@
 }
 
 TEST(DOMWindowWebDatabaseTest, WebSQLFirstPartyContext) {
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   V8TestingScope scope;
   OpenWebDatabaseInWindow("https://example.test:0/", "first_party/empty.html",
                           scope.GetExceptionState());
diff --git a/third_party/blink/renderer/modules/webshare/navigator_share_test.cc b/third_party/blink/renderer/modules/webshare/navigator_share_test.cc
index 6573494b..4439bfb 100644
--- a/third_party/blink/renderer/modules/webshare/navigator_share_test.cc
+++ b/third_party/blink/renderer/modules/webshare/navigator_share_test.cc
@@ -134,8 +134,7 @@
   }
 
  public:
-  test::TaskEnvironment task_environment{
-      test::TaskEnvironment::RealMainThreadScheduler()};
+  test::TaskEnvironment task_environment;
   MockShareService mock_share_service_;
 
   std::unique_ptr<DummyPageHolder> holder_;
diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc
index f8bc69ae8..4dbab655 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc
@@ -171,8 +171,7 @@
   }
 
  protected:
-  test::TaskEnvironment task_environment_{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment_;
   scoped_refptr<viz::TestContextProvider> test_context_provider_;
   ImageTrackingDecodeCache image_decode_cache_;
   std::unique_ptr<FakeCanvasResourceHost> host_;
diff --git a/third_party/blink/renderer/platform/graphics/canvas_hibernation_handler_test.cc b/third_party/blink/renderer/platform/graphics/canvas_hibernation_handler_test.cc
index 189a732..11da7c5 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_hibernation_handler_test.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_hibernation_handler_test.cc
@@ -64,8 +64,7 @@
   }
 
  protected:
-  test::TaskEnvironment task_environment_{
-      test::TaskEnvironment::RealMainThreadScheduler{}};
+  test::TaskEnvironment task_environment_;
   scoped_refptr<viz::TestContextProvider> test_context_provider_;
   std::unique_ptr<FakeCanvasResourceHost> host_;
 };
diff --git a/third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.cc b/third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.cc
index 7d03224..54dbdd4 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.cc
@@ -8,7 +8,9 @@
 
 #include "base/check.h"
 #include "base/command_line.h"
+#include "base/strings/string_split.h"
 #include "base/task/single_thread_task_runner.h"
+#include "gpu/config/gpu_finch_features.h"
 #include "gpu/config/gpu_switches.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/webgpu_resource_provider_cache.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
@@ -152,8 +154,7 @@
   NoopSerializer noop_serializer;
   dawn::wire::WireClient client{{.serializer = &noop_serializer}};
 
-  // Make an instance descriptor with chained structs to control which WGSL
-  // features are exposed.
+  // Control which WGSL features are exposed based on flags.
   WGPUDawnWireWGSLControl wgsl_control = {};
   wgsl_control.chain.sType = WGPUSType_DawnWireWGSLControl;
   wgsl_control.enableUnsafe = base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -165,11 +166,31 @@
   // WGSL features.
   wgsl_control.enableTesting = false;
 
+  // Additionally populate the WGSL blocklist based on the Finch feature.
+  std::vector<std::string> wgsl_unsafe_features_owned;
+  std::vector<const char*> wgsl_unsafe_features;
+
+  if (!wgsl_control.enableUnsafe) {
+    wgsl_unsafe_features_owned =
+        base::SplitString(features::kWGSLUnsafeFeatures.Get(), ",",
+                          base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+    wgsl_unsafe_features.reserve(wgsl_unsafe_features_owned.size());
+    for (const auto& f : wgsl_unsafe_features_owned) {
+      wgsl_unsafe_features.push_back(f.c_str());
+    }
+  }
+  WGPUDawnWGSLBlocklist wgsl_blocklist = {};
+  wgsl_blocklist.chain.sType = WGPUSType_DawnWGSLBlocklist;
+  wgsl_blocklist.chain.next = &wgsl_control.chain;
+  wgsl_blocklist.blocklistedFeatureCount = wgsl_unsafe_features.size();
+  wgsl_blocklist.blocklistedFeatures = wgsl_unsafe_features.data();
+
+  // Create the instance from all the chained structures and gather features
+  // from it.
   WGPUInstanceDescriptor instance_desc = {};
-  instance_desc.nextInChain = &wgsl_control.chain;
+  instance_desc.nextInChain = &wgsl_blocklist.chain;
   WGPUInstance instance = client.ReserveInstance(&instance_desc).instance;
 
-  // Gather features from the instance and release the reference we have to it.
   const DawnProcTable& procs = dawn::wire::client::GetProcs();
 
   size_t feature_count =
diff --git a/third_party/blink/renderer/platform/testing/task_environment.h b/third_party/blink/renderer/platform/testing/task_environment.h
index 8fdb5df8..b9d922d 100644
--- a/third_party/blink/renderer/platform/testing/task_environment.h
+++ b/third_party/blink/renderer/platform/testing/task_environment.h
@@ -17,15 +17,7 @@
 
 class TaskEnvironmentImpl : public base::test::TaskEnvironment {
  public:
-  // Instantiates a full featured blink::MainThreadScheduler as opposed to a
-  // simple Thread scheduler.
-  // TODO(crbug.com/1315595): Remove this once all callsites are updated.
-  struct RealMainThreadScheduler {};
-
-  struct ValidTraits {
-    explicit ValidTraits(base::test::TaskEnvironment::ValidTraits);
-    explicit ValidTraits(RealMainThreadScheduler);
-  };
+  using ValidTraits = base::test::TaskEnvironment::ValidTraits;
 
   template <typename... Traits>
     requires base::trait_helpers::AreValidTraits<ValidTraits, Traits...>
@@ -33,9 +25,7 @@
       : TaskEnvironmentImpl(CreateTaskEnvironmentWithPriorities(
             blink::scheduler::CreatePrioritySettings(),
             SubclassCreatesDefaultTaskRunner{},
-            base::trait_helpers::
-                Exclude<MainThreadType, RealMainThreadScheduler>::Filter(
-                    traits)...)) {}
+            traits...)) {}
 
   ~TaskEnvironmentImpl() override;
 
@@ -71,8 +61,6 @@
 // base::test::TaskEnvironment otherwise.
 class TaskEnvironment {
  public:
-  using RealMainThreadScheduler =
-      internal::TaskEnvironmentImpl::RealMainThreadScheduler;
   using ValidTraits = internal::TaskEnvironmentImpl::ValidTraits;
 
   template <typename... Traits>
diff --git a/third_party/blink/renderer/platform/testing/task_environment_unittest.cc b/third_party/blink/renderer/platform/testing/task_environment_unittest.cc
index b21e99cf..3935b5a8 100644
--- a/third_party/blink/renderer/platform/testing/task_environment_unittest.cc
+++ b/third_party/blink/renderer/platform/testing/task_environment_unittest.cc
@@ -18,23 +18,13 @@
   kMainThread,
 };
 
-class TaskEnvironmentTestParam : public testing::TestWithParam<SchedulerType> {
- public:
-  void SetUp() override {
-    if (GetParam() == SchedulerType::kMainThread) {
-      task_environment_.emplace(
-          test::TaskEnvironment::RealMainThreadScheduler());
-    } else {
-      task_environment_.emplace();
-    }
-  }
-
+class TaskEnvironmentTest : public testing::Test {
  protected:
-  absl::optional<test::TaskEnvironment> task_environment_;
+  test::TaskEnvironment task_environment_;
 };
 
-TEST_P(TaskEnvironmentTestParam, MainThreadTaskRunner) {
-  auto quit_closure = (*task_environment_)->QuitClosure();
+TEST_F(TaskEnvironmentTest, MainThreadTaskRunner) {
+  auto quit_closure = task_environment_->QuitClosure();
   base::ThreadPool::PostTask(
       FROM_HERE, base::BindLambdaForTesting([&]() {
         Thread::MainThread()
@@ -45,16 +35,11 @@
                        }));
       }));
 
-  (*task_environment_)->RunUntilQuit();
+  task_environment_->RunUntilQuit();
 }
 
-TEST_P(TaskEnvironmentTestParam, Isolate) {
-  EXPECT_TRUE(task_environment_->isolate());
+TEST_F(TaskEnvironmentTest, Isolate) {
+  EXPECT_TRUE(task_environment_.isolate());
 }
 
-INSTANTIATE_TEST_SUITE_P(All,
-                         TaskEnvironmentTestParam,
-                         ::testing::Values(SchedulerType::kSimple,
-                                           SchedulerType::kMainThread));
-
 }  // namespace blink
diff --git a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/OWNERS b/third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/OWNERS
similarity index 100%
rename from third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/OWNERS
rename to third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/OWNERS
diff --git a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/__init__.py b/third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/__init__.py
similarity index 100%
rename from third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/__init__.py
rename to third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/__init__.py
diff --git a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/analyzer.py b/third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/analyzer.py
similarity index 98%
rename from third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/analyzer.py
rename to third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/analyzer.py
index cf64355..ca3e035 100644
--- a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/analyzer.py
+++ b/third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/analyzer.py
@@ -5,7 +5,7 @@
 
 from typing import List
 
-from blinkpy.web_tests.fuzzy_diff_analyzer import data_types as dt
+from blinkpy.web_tests.web_test_analyzers import data_types as dt
 
 MAX_BUILDER_NUM = 5
 AVG_DURATION_THRESHOLD = 0.75
diff --git a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/analyzer_unittest.py b/third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/analyzer_unittest.py
similarity index 98%
rename from third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/analyzer_unittest.py
rename to third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/analyzer_unittest.py
index 5b6a210..7640c0cf 100644
--- a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/analyzer_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/analyzer_unittest.py
@@ -4,8 +4,8 @@
 
 import unittest
 
-from blinkpy.web_tests.fuzzy_diff_analyzer import analyzer
-from blinkpy.web_tests.fuzzy_diff_analyzer import data_types as dt
+from blinkpy.web_tests.web_test_analyzers import analyzer
+from blinkpy.web_tests.web_test_analyzers import data_types as dt
 
 
 class FuzzyMatchingAnalyzerTest(unittest.TestCase):
diff --git a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/data_types.py b/third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/data_types.py
similarity index 100%
rename from third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/data_types.py
rename to third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/data_types.py
diff --git a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/data_types_unittest.py b/third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/data_types_unittest.py
similarity index 97%
rename from third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/data_types_unittest.py
rename to third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/data_types_unittest.py
index ce2350b..6f43bb3 100644
--- a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/data_types_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/data_types_unittest.py
@@ -5,7 +5,7 @@
 import typing
 import unittest
 
-from blinkpy.web_tests.fuzzy_diff_analyzer import data_types
+from blinkpy.web_tests.web_test_analyzers import data_types
 
 
 class FuzzyDiffAnalyzerDataTypesUnittest(unittest.TestCase):
diff --git a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/fuzzy_diff_analyzer.py b/third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/fuzzy_diff_analyzer.py
similarity index 96%
rename from third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/fuzzy_diff_analyzer.py
rename to third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/fuzzy_diff_analyzer.py
index 0fc8a349..99650724 100644
--- a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/fuzzy_diff_analyzer.py
+++ b/third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/fuzzy_diff_analyzer.py
@@ -21,9 +21,9 @@
 from blinkpy.common.host import Host
 from blinkpy.common.net.luci_auth import LuciAuth
 from blinkpy.w3c.monorail import MonorailAPI
-from blinkpy.web_tests.fuzzy_diff_analyzer import analyzer
-from blinkpy.web_tests.fuzzy_diff_analyzer import queries
-from blinkpy.web_tests.fuzzy_diff_analyzer import results
+from blinkpy.web_tests.web_test_analyzers import analyzer
+from blinkpy.web_tests.web_test_analyzers import queries
+from blinkpy.web_tests.web_test_analyzers import results
 
 
 DASHBOARD_BASE_URL = 'https://dashboards.corp.google.com/image_comparison'\
diff --git a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/queries.py b/third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/queries.py
similarity index 100%
rename from third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/queries.py
rename to third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/queries.py
diff --git a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/queries_unittest.py b/third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/queries_unittest.py
similarity index 98%
rename from third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/queries_unittest.py
rename to third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/queries_unittest.py
index 23fcb3fa..3edd5bf7 100644
--- a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/queries_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/queries_unittest.py
@@ -6,7 +6,7 @@
 import unittest
 import unittest.mock as mock
 
-from blinkpy.web_tests.fuzzy_diff_analyzer import queries
+from blinkpy.web_tests.web_test_analyzers import queries
 from flake_suppressor_common import unittest_utils as uu
 
 QUERY_DATA = [{
diff --git a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/results.py b/third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/results.py
similarity index 97%
rename from third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/results.py
rename to third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/results.py
index edfd5294..d461cd0f 100644
--- a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/results.py
+++ b/third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/results.py
@@ -8,7 +8,7 @@
 
 from flake_suppressor_common import common_typing as ct
 from flake_suppressor_common import tag_utils
-from blinkpy.web_tests.fuzzy_diff_analyzer import data_types as dt
+from blinkpy.web_tests.web_test_analyzers import data_types as dt
 
 
 class ResultProcessor:
diff --git a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/results_unittest.py b/third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/results_unittest.py
similarity index 97%
rename from third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/results_unittest.py
rename to third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/results_unittest.py
index cf806c3..a857712 100644
--- a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/results_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/results_unittest.py
@@ -4,8 +4,8 @@
 
 import unittest
 
-from blinkpy.web_tests.fuzzy_diff_analyzer import data_types
-from blinkpy.web_tests.fuzzy_diff_analyzer import results
+from blinkpy.web_tests.web_test_analyzers import data_types
+from blinkpy.web_tests.web_test_analyzers import results
 from flake_suppressor_common import tag_utils as common_tag_utils
 from flake_suppressor_common import unittest_utils as uu
 
diff --git a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/slow_test_analyzer.py b/third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/slow_test_analyzer.py
similarity index 94%
rename from third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/slow_test_analyzer.py
rename to third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/slow_test_analyzer.py
index e6a0f255..07be2c2 100644
--- a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/slow_test_analyzer.py
+++ b/third_party/blink/tools/blinkpy/web_tests/web_test_analyzers/slow_test_analyzer.py
@@ -19,9 +19,9 @@
 
 import argparse
 
-from blinkpy.web_tests.fuzzy_diff_analyzer import analyzer
-from blinkpy.web_tests.fuzzy_diff_analyzer import queries
-from blinkpy.web_tests.fuzzy_diff_analyzer import results
+from blinkpy.web_tests.web_test_analyzers import analyzer
+from blinkpy.web_tests.web_test_analyzers import queries
+from blinkpy.web_tests.web_test_analyzers import results
 
 
 def ParseArgs() -> argparse.Namespace:
diff --git a/third_party/blink/tools/run_fuzzy_diff_analyzer.py b/third_party/blink/tools/run_fuzzy_diff_analyzer.py
index 5a66bb8..4ec9b0c 100755
--- a/third_party/blink/tools/run_fuzzy_diff_analyzer.py
+++ b/third_party/blink/tools/run_fuzzy_diff_analyzer.py
@@ -3,7 +3,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-from blinkpy.web_tests.fuzzy_diff_analyzer import (fuzzy_diff_analyzer)
+from blinkpy.web_tests.web_test_analyzers import fuzzy_diff_analyzer
 
 import sys
 
diff --git a/third_party/blink/tools/run_slow_test_analyzer.py b/third_party/blink/tools/run_slow_test_analyzer.py
index e4d17287..0fa31c2 100755
--- a/third_party/blink/tools/run_slow_test_analyzer.py
+++ b/third_party/blink/tools/run_slow_test_analyzer.py
@@ -3,7 +3,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-from blinkpy.web_tests.fuzzy_diff_analyzer import slow_test_analyzer
+from blinkpy.web_tests.web_test_analyzers import slow_test_analyzer
 
 import sys
 
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index bdff7d0..dea24b6 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1280,6 +1280,10 @@
 crbug.com/750992 [ Linux ] external/wpt/css/css-writing-modes/sizing-orthog-vrl-in-htb-020.xht [ Failure ]
 crbug.com/750992 [ Win ] external/wpt/css/css-writing-modes/sizing-orthog-vrl-in-htb-020.xht [ Failure ]
 
+# PEPC crash
+crbug.com/1512722 external/wpt/html/semantics/permission-element/no-end-tag-no-contents.html [ Crash Failure ]
+crbug.com/1512722 virtual/permission-element/external/wpt/html/semantics/permission-element/no-end-tag-no-contents.html [ Pass ]
+
 # These tests are mismatch tests which means they will only pass if the rendered page is not the
 # same between vertical and horizontal writing mode. Failing the tests is equivalent to testing
 # that the appearance is the same. For the virtual version, we disable the features
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 694d178..400a0b2 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -2480,11 +2480,18 @@
     "prefix": "permission-element",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/html/semantics/permission-element"],
-    "exclusive_tests": "ALL",
     "args": ["--enable-features=PermissionElement"],
     "owners": ["permissions-core@google.com"],
     "expires": "Jul 1, 2024"
   },
+  {
+    "prefix": "permission-element-disabled",
+    "platforms": ["Linux"],
+    "bases": [],
+    "args": ["--disable-features=PermissionElement"],
+    "owners": ["permissions-core@google.com"],
+    "expires": "Jul 1, 2024"
+  },
   "The GenericSensorExtraClasses feature is controlled by a flag, which has ",
   "an expiration date. |expires| below is set to 'never' to avoid having to ",
   "manage the expiration date in two locations.",
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index 8c2d209e..c5c421cf 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -291174,6 +291174,10 @@
      "b0f50d1bbb4136ae68db01e2f5e32836371a7077",
      []
     ],
+    "WEB_FEATURES.yml": [
+     "6b7ff09a1209a369ff27afab42c89c7ef59fc31f",
+     []
+    ],
     "content-security-policy.https.window-expected.txt": [
      "1f12b21050ae83dd11f575bd394b94b36b2f2732",
      []
@@ -303569,6 +303573,10 @@
       "97e2659bf8cff713dc731eec03ac942794cc5fd2",
       []
      ],
+     "WEB_FEATURES.yml": [
+      "2e4c34982a2647d594213b283bb7d3d4b9af1e56",
+      []
+     ],
      "anchor-center-002-ref.html": [
       "40ccc2b044b3da3be44582522d99e5a138b6f354",
       []
@@ -307772,6 +307780,10 @@
        "2fa113f5f777ecbc33fcb295316c42fd7dfa8f71",
        []
       ],
+      "WEB_FEATURES.yml": [
+       "445ceb373f006b2741029c1360416dee2d3d7057",
+       []
+      ],
       "change-display-in-container-ref.html": [
        "8dd3b8b2c1dea6230357f8ff6ec1225154650094",
        []
@@ -307864,6 +307876,10 @@
       ]
      },
      "content-visibility": {
+      "WEB_FEATURES.yml": [
+       "345619e8b7108b9f528497559886aca0eeacca12",
+       []
+      ],
       "container-focus-ref.html": [
        "402b689010d320277b20d73da16958d1c54fc764",
        []
@@ -320584,6 +320600,10 @@
       }
      },
      "animation": {
+      "WEB_FEATURES.yml": [
+       "169b731925a7c9f5bb176c5407b001de32f4f9ba",
+       []
+      ],
       "grid-template-columns-001-ref.html": [
        "1d53815f37dd9e1809757074ef4a9aad557877e2",
        []
@@ -321928,6 +321948,10 @@
       []
      ],
      "image-set": {
+      "WEB_FEATURES.yml": [
+       "91070c242eab7d680dfe3efc8c73b40cc8047ad0",
+       []
+      ],
       "image-set-resolution-001-ref.html": [
        "46c4d729ed59525b1a138f1f60aa6e6074251211",
        []
@@ -322926,6 +322950,10 @@
       ]
      },
      "text-box-trim": {
+      "WEB_FEATURES.yml": [
+       "e9a2fc218b369825c991e3109986481a922e671f",
+       []
+      ],
       "text-box-trim-half-leading-inline-box-001-ref.html": [
        "54df108fb9c581638784b1b28cd120fc59fa6c4e",
        []
@@ -325581,6 +325609,10 @@
      }
     },
     "css-nesting": {
+     "WEB_FEATURES.yml": [
+      "297d31d99d71aa5fbfa7afe6a2dc824eaa58a19c",
+      []
+     ],
      "conditional-properties-ref.html": [
       "0285acbf33f9b9e360d715db33f4a56bbb235e87",
       []
@@ -330485,6 +330517,10 @@
       "359219c09965b90066e4fb31d952d621d0d0dc5b",
       []
      ],
+     "WEB_FEATURES.yml": [
+      "551546706182927dd2cf150bac1dd19525f61029",
+      []
+     ],
      "charset": {
       "MANIFEST": [
        "4bc83f6e70479f46d3066805bdc61f7f33d727f6",
@@ -333394,6 +333430,10 @@
       ]
      },
      "text-indent": {
+      "WEB_FEATURES.yml": [
+       "7933ffd974ea1e45b5df803a2337bef647f73163",
+       []
+      ],
       "reference": {
        "anonymous-flex-grid-item-001-ref.html": [
         "517f9e65fde0f2951fb8175b77a13eaf3514a62d",
@@ -339795,6 +339835,10 @@
       "a1747aadc086e75733c15242826d7631b0c95ead",
       []
      ],
+     "WEB_FEATURES.yml": [
+      "b06c71a226e4232c9c500599c0b76c2791c9eef6",
+      []
+     ],
      "reference": {
       "variable-reference-without-whitespace-ref.html": [
        "3d9aaed6b129725cb5190afd9f19aefae834f37f",
@@ -339923,6 +339967,10 @@
       "92f4c431c19b1194009c9b591111f3ee70a34522",
       []
      ],
+     "WEB_FEATURES.yml": [
+      "e1df1b8c670205931df252d4956287277f97700d",
+      []
+     ],
      "animating-new-content-ref.html": [
       "eae9e2c4711e455040efef37f8315b94c7663a32",
       []
@@ -346100,6 +346148,10 @@
      "e30f6fc97f95f78e10c0ada540fbe17528512b63",
      []
     ],
+    "WEB_FEATURES.yml": [
+     "37708a919e550d0138374fd2b25b34baddbbb0e5",
+     []
+    ],
     "cross-realm-callback-report-exception-expected.txt": [
      "7b3162d79339f7fdc7ddabda3bc008e91baf4145",
      []
@@ -346677,6 +346729,10 @@
     "META.yml": [
      "879c08803e18123863e623d23de77d2e67d1978c",
      []
+    ],
+    "WEB_FEATURES.yml": [
+     "cf364db88ef847fae3df7ae1803d9ef7dd01f1c3",
+     []
     ]
    },
    "document-policy": {
@@ -359810,6 +359866,10 @@
        "d0524194c9186da948d150da7b36f0f1144a61f9",
        []
       ],
+      "WEB_FEATURES.yml": [
+       "b1f003a745f43bce7e24744902c9668a65fa5338",
+       []
+      ],
       "fill-and-stroke-styles": {
        "2d.gradient.interpolate.alpha.png": [
         "af5ac0f07d64e7598e0ea6a8e37cff2a5c4ea2a0",
@@ -367567,7 +367627,7 @@
        },
        "support": {
         "hit-test.js": [
-         "54cda3e5cd183f64254919451e52f04ea1087a9f",
+         "82a98f1c3574aa894b9b3bc89d09468737c3511f",
          []
         ]
        }
@@ -368973,6 +369033,10 @@
         "12964ec475f8051987f0e0b3b21da40c24deb907",
         []
        ],
+       "WEB_FEATURES.yml": [
+        "f270236cff5e0283ed39d423280b99d69defb204",
+        []
+       ],
        "backdrop-descendant-selector-ref.html": [
         "70d84c21ff4b01ef933172c676679e04b9333f14",
         []
@@ -380394,6 +380458,10 @@
      "8df9be5e5b1961296346b4c98a295acbe0fd97c0",
      []
     ],
+    "WEB_FEATURES.yml": [
+     "e895260b8ba64f5fde06867a0fd22b7f97c4f893",
+     []
+    ],
     "resources": {
      "picture-in-picture-helpers.js": [
       "7561944a18d0296b33dbb3acb1f3a82b1512d08f",
@@ -383688,6 +383756,10 @@
      "fc6bc8634586ded123fed22ca840e5d1128f7302",
      []
     ],
+    "WEB_FEATURES.yml": [
+     "428aeee63a2a8a03f720d24edb7d743aa7ceab2e",
+     []
+    ],
     "element-set-sanitized-html.https-expected.txt": [
      "a312ec355b1eef9dad804417b18ccc957627c0f3",
      []
@@ -387250,6 +387322,10 @@
      "8fb0a9b995d6289bb28582fa01e6bb092afa5dda",
      []
     ],
+    "WEB_FEATURES.yml": [
+     "171923c067225ac7334b8011e7deaf347538952a",
+     []
+    ],
     "declarative": {
      "clonable.window-expected.txt": [
       "1bc695efb2f0e4a34cabc11a721e98965b8296f1",
@@ -392634,6 +392710,10 @@
      "c41e0e048efe704917b05894ab72c3f60f5a9a97",
      []
     ],
+    "WEB_FEATURES.yml": [
+     "be78a70b81c0e0fdf766ace2e19f4de77d29aeba",
+     []
+    ],
     "animation-model": {
      "animation-types": {
       "accumulation-per-property-001-expected.txt": [
@@ -394242,7 +394322,7 @@
         ]
        },
        "conftest.py": [
-        "fb6dcc45dd779a1cc790a95607781b01254fa3b3",
+        "184073a53ab5b68b623187bfcf5d30670e4fca48",
         []
        ],
        "continue_request": {
@@ -394950,7 +395030,7 @@
         []
        ],
        "authentication.py": [
-        "d3c95a948f093c64f2770c79f38de9fca5441014",
+        "2526a5a4c2ca5d1f45db4a93a9b911e4ec0d6236",
         []
        ],
        "cached.py": [
@@ -395054,6 +395134,10 @@
      "9c287fe0b65d5efea94aad02e16f6a8f4d965348",
      []
     ],
+    "WEB_FEATURES.yml": [
+     "7453658f782db1f9cd9d2ada6956bbf0dc3ce821",
+     []
+    ],
     "idlharness.https.window-expected.txt": [
      "4a67d9117621532ad223ed3c7e201706e400bbdb",
      []
@@ -395181,6 +395265,10 @@
      []
     ],
     "broadcastchannel": {
+     "WEB_FEATURES.yml": [
+      "378ed57dc52d077675669200b20dcbe833b007a7",
+      []
+     ],
      "opaque-origin-expected.txt": [
       "a1d3fec2c9efc182cdc0d48a347414a01a3de54e",
       []
@@ -397148,6 +397236,10 @@
      "543d876e01d2b1612538825082ef0650401bc6e3",
      []
     ],
+    "WEB_FEATURES.yml": [
+     "057d226047cb6e812d1a3fb5b5d7eb7a2bae5e6b",
+     []
+    ],
     "back-forward-cache-with-closed-webtransport-connection-ccns.https.tentative.window-expected.txt": [
      "9e53f0772adef3bbedd2ac787f07c0502ef71ce5",
      []
@@ -702153,8 +702245,15 @@
         ]
        },
        "continue_with_auth": {
+        "action.py": [
+         "1c256aaeaa184914dc512c8f867f05d7de525e14",
+         [
+          null,
+          {}
+         ]
+        ],
         "invalid.py": [
-         "ea188cbde88d1874bf3401a6507ef641144045fc",
+         "dc21d0bc53c12fc4d9b3328307820dc97d5b558d",
          [
           null,
           {}
diff --git a/third_party/blink/web_tests/external/wpt/background-fetch/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/background-fetch/WEB_FEATURES.yml
new file mode 100644
index 0000000..6b7ff09a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/background-fetch/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: background-fetch
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/WEB_FEATURES.yml
new file mode 100644
index 0000000..2e4c3498
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: anchor-positioning
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/WEB_FEATURES.yml
new file mode 100644
index 0000000..445ceb3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: container-queries
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/WEB_FEATURES.yml
new file mode 100644
index 0000000..345619e8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: content-visibility
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/animation/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/css/css-grid/animation/WEB_FEATURES.yml
new file mode 100644
index 0000000..169b7319
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/animation/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: grid-animation
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-images/image-set/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/css/css-images/image-set/WEB_FEATURES.yml
new file mode 100644
index 0000000..91070c24
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-images/image-set/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: image-set
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/WEB_FEATURES.yml
new file mode 100644
index 0000000..e9a2fc2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: text-box-trim
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-nesting/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/css/css-nesting/WEB_FEATURES.yml
new file mode 100644
index 0000000..297d31d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-nesting/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: nesting
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-syntax/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/css/css-syntax/WEB_FEATURES.yml
new file mode 100644
index 0000000..5515467
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-syntax/WEB_FEATURES.yml
@@ -0,0 +1,6 @@
+features:
+- name: nesting
+  files:
+  - custom-property-rule-ambiguity.html
+  - trailing-braces.html
+  - var-with-blocks.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-indent/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/css/css-text/text-indent/WEB_FEATURES.yml
new file mode 100644
index 0000000..7933ffd9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-indent/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: text-indent
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-variables/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/css/css-variables/WEB_FEATURES.yml
new file mode 100644
index 0000000..b06c71a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-variables/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: custom-properties
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/WEB_FEATURES.yml
new file mode 100644
index 0000000..e1df1b8c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: view-transitions
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/custom-elements/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/custom-elements/WEB_FEATURES.yml
new file mode 100644
index 0000000..37708a9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/custom-elements/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: custom-elements
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/document-picture-in-picture/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/document-picture-in-picture/WEB_FEATURES.yml
new file mode 100644
index 0000000..cf364db
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/document-picture-in-picture/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: document-picture-in-picture
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/WEB_FEATURES.yml
new file mode 100644
index 0000000..b1f003a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: offscreen-canvas
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-area-element/support/hit-test.js b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-area-element/support/hit-test.js
index 54cda3e..82a98f1 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-area-element/support/hit-test.js
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-area-element/support/hit-test.js
@@ -20,7 +20,7 @@
 onload = function() {
   tests.forEach(function(t) {
     test(function(t_obj) {
-      if (area.shape === null) {
+      if (t.shape === null) {
         area.removeAttribute('shape');
       } else {
         area.shape = t.shape;
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/WEB_FEATURES.yml
new file mode 100644
index 0000000..f270236
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: dialog
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/picture-in-picture/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/picture-in-picture/WEB_FEATURES.yml
new file mode 100644
index 0000000..e895260
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/picture-in-picture/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: picture-in-picture
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/sanitizer-api/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/sanitizer-api/WEB_FEATURES.yml
new file mode 100644
index 0000000..428aeee
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/sanitizer-api/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: sanitizer
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/shadow-dom/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/shadow-dom/WEB_FEATURES.yml
new file mode 100644
index 0000000..171923c0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/shadow-dom/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: shadow-dom
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/web-animations/WEB_FEATURES.yml
new file mode 100644
index 0000000..be78a70
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/web-animations/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: web-animations
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/conftest.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/conftest.py
index fb6dcc45..184073a 100644
--- a/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/conftest.py
+++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/conftest.py
@@ -33,7 +33,7 @@
     for intercept in intercepts:
         try:
             await bidi_session.network.remove_intercept(intercept=intercept)
-        except (NoSuchInterceptException):
+        except NoSuchInterceptException:
             # Ignore exceptions in case a specific intercept was already removed
             # during the test.
             pass
@@ -44,7 +44,10 @@
     """Perform a fetch from the page of the provided context, default to the
     top context.
     """
-    async def fetch(url, method="GET", headers=None, context=top_context, timeout_in_seconds=3):
+
+    async def fetch(
+        url, method="GET", headers=None, context=top_context, timeout_in_seconds=3
+    ):
         method_arg = f"method: '{method}',"
 
         headers_arg = ""
@@ -76,7 +79,12 @@
 
 @pytest_asyncio.fixture
 async def setup_network_test(
-    bidi_session, subscribe_events, wait_for_event, wait_for_future_safe, top_context, url
+    bidi_session,
+    subscribe_events,
+    wait_for_event,
+    wait_for_future_safe,
+    top_context,
+    url,
 ):
     """Navigate the current top level context to the provided url and subscribe
     to network.beforeRequestSent.
@@ -131,12 +139,26 @@
 async def setup_blocked_request(
     setup_network_test, url, add_intercept, fetch, wait_for_event
 ):
-    async def setup_blocked_request(phase):
+    """Creates an intercept for the provided phase, sends a fetch request that
+    should be blocked by this intercept and resolves when the corresponding
+    event is received.
+
+    For the "authRequired" phase, the request will be sent to the authentication
+    http handler. The optional arguments username, password and realm can be used
+    to configure the handler.
+
+    Returns the `request` id of the intercepted request.
+    """
+
+    async def setup_blocked_request(
+        phase, username="user", password="password", realm="test"
+    ):
         await setup_network_test(events=[f"network.{phase}"])
 
         if phase == "authRequired":
             blocked_url = url(
-                "/webdriver/tests/support/http_handlers/authentication.py?realm=testrealm"
+                "/webdriver/tests/support/http_handlers/authentication.py?"
+                f"username={username}&password={password}&realm={realm}"
             )
         else:
             blocked_url = url(PAGE_EMPTY_TEXT)
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/continue_with_auth/action.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/continue_with_auth/action.py
new file mode 100644
index 0000000..1c256aa
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/continue_with_auth/action.py
@@ -0,0 +1,180 @@
+import pytest
+import webdriver.bidi.error as error
+from webdriver.bidi.modules.network import AuthCredentials
+from webdriver.error import TimeoutException
+
+from tests.support.sync import AsyncPoll
+from .. import (
+    assert_response_event,
+    AUTH_REQUIRED_EVENT,
+    PAGE_EMPTY_TEXT,
+    RESPONSE_COMPLETED_EVENT,
+)
+
+pytestmark = pytest.mark.asyncio
+
+
+async def test_cancel(
+    setup_blocked_request, subscribe_events, wait_for_event, bidi_session, url
+):
+    request = await setup_blocked_request("authRequired")
+    await subscribe_events(events=[RESPONSE_COMPLETED_EVENT])
+
+    on_response_completed = wait_for_event(RESPONSE_COMPLETED_EVENT)
+    await bidi_session.network.continue_with_auth(request=request, action="cancel")
+    await on_response_completed
+
+    response_event = await on_response_completed
+    assert_response_event(
+        response_event,
+        expected_response={
+            "status": 401,
+            "statusText": "Unauthorized",
+        },
+    )
+
+
+async def test_default(
+    setup_blocked_request, subscribe_events, wait_for_event, bidi_session, url
+):
+    request = await setup_blocked_request("authRequired")
+
+    # Additionally subscribe to all network events
+    await subscribe_events(events=["network"])
+
+    # Track all received network.responseCompleted events in the events array
+    events = []
+
+    async def on_event(method, data):
+        events.append(data)
+
+    remove_listener = bidi_session.add_event_listener(
+        RESPONSE_COMPLETED_EVENT, on_event
+    )
+
+    # continueWithAuth using action "default" should show the authentication
+    # prompt and no new network event should be generated.
+    await bidi_session.network.continue_with_auth(request=request, action="default")
+
+    wait = AsyncPoll(bidi_session, timeout=0.5)
+    with pytest.raises(TimeoutException):
+        await wait.until(lambda _: len(events) > 0)
+
+    remove_listener()
+
+
+async def test_provideCredentials(
+    setup_blocked_request, subscribe_events, bidi_session, url
+):
+    # Setup unique username / password because browsers cache credentials.
+    username = "test_provideCredentials"
+    password = "test_provideCredentials_password"
+    request = await setup_blocked_request("authRequired", username=username, password=password)
+
+    # Additionally subscribe to network.responseCompleted
+    await subscribe_events(events=[RESPONSE_COMPLETED_EVENT])
+
+    # Track all received network.responseCompleted events in the events array
+    events = []
+
+    async def on_event(method, data):
+        events.append(data)
+
+    remove_listener = bidi_session.add_event_listener(
+        RESPONSE_COMPLETED_EVENT, on_event
+    )
+
+    credentials = AuthCredentials(username=username, password=password)
+    await bidi_session.network.continue_with_auth(
+        request=request, action="provideCredentials", credentials=credentials
+    )
+
+    wait = AsyncPoll(bidi_session, message="Didn't receive response completed events")
+    await wait.until(lambda _: len(events) >= 2)
+    assert len(events) == 2
+
+    assert_response_event(
+        events[0],
+        expected_response={
+            "status": 401,
+            "statusText": "Unauthorized",
+        },
+    )
+
+    assert_response_event(
+        events[1],
+        expected_response={
+            "status": 200,
+            "statusText": "OK",
+        },
+    )
+
+    remove_listener()
+
+
+async def test_provideCredentials_wrong_credentials(
+    setup_blocked_request, subscribe_events, bidi_session, wait_for_event, url
+):
+    # Setup unique username / password because browsers cache credentials.
+    username = "test_provideCredentials_wrong_credentials"
+    password = "test_provideCredentials_wrong_credentials_password"
+    request = await setup_blocked_request("authRequired", username=username, password=password)
+
+    # Additionally subscribe to network.responseCompleted
+    await subscribe_events(events=[RESPONSE_COMPLETED_EVENT])
+
+    # Track all received network.responseCompleted events in the events array
+    events = []
+
+    async def on_event(method, data):
+        events.append(data)
+
+    remove_listener = bidi_session.add_event_listener(
+        RESPONSE_COMPLETED_EVENT, on_event
+    )
+
+    on_auth_required = wait_for_event(AUTH_REQUIRED_EVENT)
+
+    wrong_credentials = AuthCredentials(username=username, password="wrong_password")
+    await bidi_session.network.continue_with_auth(
+        request=request, action="provideCredentials", credentials=wrong_credentials
+    )
+
+    # We expect to get another authRequired event after providing wrong credentials
+    await on_auth_required
+
+    # Continue with the correct credentials
+    correct_credentials = AuthCredentials(username=username, password=password)
+    await bidi_session.network.continue_with_auth(
+        request=request, action="provideCredentials", credentials=correct_credentials
+    )
+
+    wait = AsyncPoll(bidi_session, message="Didn't receive response completed events")
+    await wait.until(lambda _: len(events) >= 3)
+    assert len(events) == 3
+
+    assert_response_event(
+        events[0],
+        expected_response={
+            "status": 401,
+            "statusText": "Unauthorized",
+        },
+    )
+
+    assert_response_event(
+        events[1],
+        expected_response={
+            "status": 401,
+            "statusText": "Unauthorized",
+        },
+    )
+
+    assert_response_event(
+        events[2],
+        expected_response={
+            "status": 200,
+            "statusText": "OK",
+        },
+    )
+
+    remove_listener()
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/continue_with_auth/invalid.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/continue_with_auth/invalid.py
index ea188cb..dc21d0b 100644
--- a/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/continue_with_auth/invalid.py
+++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/continue_with_auth/invalid.py
@@ -46,6 +46,46 @@
         await bidi_session.network.continue_with_auth(request=request, action="cancel")
 
 
+async def test_params_request_no_such_request_after_cancel(
+    setup_blocked_request, bidi_session, subscribe_events, wait_for_event
+):
+    request = await setup_blocked_request("authRequired")
+
+    await subscribe_events(events=[RESPONSE_COMPLETED_EVENT])
+    on_response_completed = wait_for_event(RESPONSE_COMPLETED_EVENT)
+
+    await bidi_session.network.continue_with_auth(request=request, action="cancel")
+    await on_response_completed
+
+    with pytest.raises(error.NoSuchRequestException):
+        await bidi_session.network.continue_with_auth(request=request, action="cancel")
+
+
+async def test_params_request_no_such_request_after_provideCredentials(
+    setup_blocked_request, bidi_session, subscribe_events, wait_for_event
+):
+    # Setup unique username / password because browsers cache credentials.
+    username = "test_params_request_no_such_request_after_provideCredentials"
+    password = "test_params_request_no_such_request_after_provideCredentials_password"
+    request = await setup_blocked_request("authRequired", username=username, password=password)
+
+    await subscribe_events(events=[RESPONSE_COMPLETED_EVENT])
+    on_response_completed = wait_for_event(RESPONSE_COMPLETED_EVENT)
+
+    credentials = {
+        "type": "password",
+        "username": username,
+        "password": password,
+    }
+    await bidi_session.network.continue_with_auth(
+        request=request, action="provideCredentials", credentials=credentials
+    )
+    await on_response_completed
+
+    with pytest.raises(error.NoSuchRequestException):
+        await bidi_session.network.continue_with_auth(request=request, action="cancel")
+
+
 @pytest.mark.parametrize("value", [None, False, 42, {}, []])
 async def test_params_action_invalid_type(setup_blocked_request, bidi_session, value):
     request = await setup_blocked_request("authRequired")
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/support/http_handlers/authentication.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/support/http_handlers/authentication.py
index d3c95a9..2526a5a4 100644
--- a/third_party/blink/web_tests/external/wpt/webdriver/tests/support/http_handlers/authentication.py
+++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/support/http_handlers/authentication.py
@@ -10,10 +10,18 @@
 
 
 def main(request, response):
-    user = request.auth.username
+    username = request.auth.username
     password = request.auth.password
 
-    if user == b"user" and password == b"password":
+    expected_username = "user"
+    if b"username" in request.GET:
+        expected_username = request.GET.first(b"username")
+
+    expected_password = "password"
+    if b"password" in request.GET:
+        expected_password = request.GET.first(b"password")
+
+    if username == expected_username and password == expected_password:
         return b"Authentication done"
 
     realm = b"test"
@@ -22,4 +30,4 @@
 
     return ((401, b"Unauthorized"),
             [(b"WWW-Authenticate", b'Basic realm="' + realm + b'"')],
-            b"Please login with credentials 'user' and 'password'")
+            f"Please login with credentials '{expected_username}' and '{expected_password}'")
diff --git a/third_party/blink/web_tests/external/wpt/webhid/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/webhid/WEB_FEATURES.yml
new file mode 100644
index 0000000..7453658
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webhid/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: webhid
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/webmessaging/broadcastchannel/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/webmessaging/broadcastchannel/WEB_FEATURES.yml
new file mode 100644
index 0000000..378ed57
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webmessaging/broadcastchannel/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: broadcast-channel
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/webtransport/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/webtransport/WEB_FEATURES.yml
new file mode 100644
index 0000000..057d226
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webtransport/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: webtransport
+  files: "**"
diff --git a/third_party/blink/web_tests/platform/linux-chrome/external/wpt/webdriver/tests/bidi/network/continue_with_auth/action-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/external/wpt/webdriver/tests/bidi/network/continue_with_auth/action-expected.txt
new file mode 100644
index 0000000..f372305
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux-chrome/external/wpt/webdriver/tests/bidi/network/continue_with_auth/action-expected.txt
@@ -0,0 +1,3 @@
+This is a wdspec test.
+Harness Error. harness_status.status = 1 , harness_status.message = 
+Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/dynamic-color-scheme-change-expected.png b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/dynamic-color-scheme-change-expected.png
index f97e03c..0b51866 100644
--- a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/dynamic-color-scheme-change-expected.png
+++ b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/dynamic-color-scheme-change-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/horizontal-scrollbar-basic-expected.png b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/horizontal-scrollbar-basic-expected.png
index 19cd2f45..25187918 100644
--- a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/horizontal-scrollbar-basic-expected.png
+++ b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/horizontal-scrollbar-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dark-mode/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dark-mode/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
index 3b227a8..70b1e1b0 100644
--- a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dark-mode/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
+++ b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dark-mode/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dsf-150/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dsf-150/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
index 2f492c0..d5e06e3 100644
--- a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dsf-150/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
+++ b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dsf-150/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dsf-200/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dsf-200/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
index 22cd2e8..aee20560 100644
--- a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dsf-200/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
+++ b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dsf-200/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-hc/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-hc/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
index a04c81e..43a764f 100644
--- a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-hc/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
+++ b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-hc/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-hc/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-hc/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
index d5f6cdb..48ef571 100644
--- a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-hc/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
+++ b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-hc/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/fluent-overlay-scrollbar-dark-mode/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png b/third_party/blink/web_tests/virtual/fluent-overlay-scrollbar-dark-mode/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
index 5d265b9c..5d7820c7 100644
--- a/third_party/blink/web_tests/virtual/fluent-overlay-scrollbar-dark-mode/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
+++ b/third_party/blink/web_tests/virtual/fluent-overlay-scrollbar-dark-mode/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/fluent-overlay-scrollbar-hc/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png b/third_party/blink/web_tests/virtual/fluent-overlay-scrollbar-hc/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
index 5ae7797..4a68b3b0 100644
--- a/third_party/blink/web_tests/virtual/fluent-overlay-scrollbar-hc/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
+++ b/third_party/blink/web_tests/virtual/fluent-overlay-scrollbar-hc/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/fluent-overlay-scrollbar/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png b/third_party/blink/web_tests/virtual/fluent-overlay-scrollbar/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
index 3159c6cc..c140fa3 100644
--- a/third_party/blink/web_tests/virtual/fluent-overlay-scrollbar/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
+++ b/third_party/blink/web_tests/virtual/fluent-overlay-scrollbar/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/fluent-overlay-scrollbar/visual/hover-over-main-thread-expected.png b/third_party/blink/web_tests/virtual/fluent-overlay-scrollbar/visual/hover-over-main-thread-expected.png
index 03e5b45..8f30a60 100644
--- a/third_party/blink/web_tests/virtual/fluent-overlay-scrollbar/visual/hover-over-main-thread-expected.png
+++ b/third_party/blink/web_tests/virtual/fluent-overlay-scrollbar/visual/hover-over-main-thread-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/fluent-overlay-scrollbar/visual/scrollbar-show-tickmarks-expected.png b/third_party/blink/web_tests/virtual/fluent-overlay-scrollbar/visual/scrollbar-show-tickmarks-expected.png
index 5619c21..4cbf43e6 100644
--- a/third_party/blink/web_tests/virtual/fluent-overlay-scrollbar/visual/scrollbar-show-tickmarks-expected.png
+++ b/third_party/blink/web_tests/virtual/fluent-overlay-scrollbar/visual/scrollbar-show-tickmarks-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/permission-element-disabled/permission-disabled.html b/third_party/blink/web_tests/virtual/permission-element-disabled/permission-disabled.html
new file mode 100644
index 0000000..bec80ce
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/permission-element-disabled/permission-disabled.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+
+<!-- WHEN DISABLED, the permission element should behave as HTMLUnknownElement. -->
+
+<div id=test><permission>TEXT</permission></div>
+
+<script>
+test(function(){
+  const test = document.getElementById('test');
+  assert_equals(test.childNodes.length,1,'Permission element should allow children');
+  const permissionEl = test.firstElementChild;
+  assert_true(permissionEl instanceof HTMLUnknownElement,'Permission element should be an HTMLUnknownElement');
+  const permissionChild = permissionEl.firstChild;
+  assert_true(permissionChild instanceof Text,'Permission element should allow children');
+  assert_equals(permissionChild.data,'TEXT','Permission element should allow children');
+}, "When the Permission element feature is disabled, <permission> should be an HTMLUnknownElement");
+</script>
+
diff --git a/third_party/catapult b/third_party/catapult
index 2298e63..61af87d 160000
--- a/third_party/catapult
+++ b/third_party/catapult
@@ -1 +1 @@
-Subproject commit 2298e6389913688b2fee8100c4535053d627ef8c
+Subproject commit 61af87d894922b368c4733137916ecfaaa607fea
diff --git a/third_party/chromite b/third_party/chromite
index e8263ad..d408307 160000
--- a/third_party/chromite
+++ b/third_party/chromite
@@ -1 +1 @@
-Subproject commit e8263ad9ebd447f97efbe1dee2df803ac0298ca9
+Subproject commit d4083072a7a2976fcbbd44ed55dfac4d574c7497
diff --git a/third_party/devtools-frontend-internal b/third_party/devtools-frontend-internal
index 457fec8b..6b248f3 160000
--- a/third_party/devtools-frontend-internal
+++ b/third_party/devtools-frontend-internal
@@ -1 +1 @@
-Subproject commit 457fec8b5b9ff390f9e7a8e64f8a886d97cbe1f9
+Subproject commit 6b248f365bc8723b398e68704df495ecfbf3f8ee
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src
index c67fdad..891806c 160000
--- a/third_party/devtools-frontend/src
+++ b/third_party/devtools-frontend/src
@@ -1 +1 @@
-Subproject commit c67fdadcd104ba82740a25feed4fec2931b5f6f3
+Subproject commit 891806c2cf2bfe370e5e865269042afafbf9a569
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium
index 34fad56..91067d3 100644
--- a/third_party/freetype/README.chromium
+++ b/third_party/freetype/README.chromium
@@ -1,7 +1,7 @@
 Name: FreeType
 URL: http://www.freetype.org/
-Version: VER-2-13-2-92-g8eab51101
-Revision: 8eab511017a65026985523cab14aff07f1bb9746
+Version: VER-2-13-2-93-gca76683b7
+Revision: ca76683b781db5d06ef1a0e2cb62a767e7dbe626
 CPEPrefix: cpe:/a:freetype:freetype:2.13.2
 License: Custom license "inspired by the BSD, Artistic, and IJG (Independent
          JPEG Group) licenses"
diff --git a/third_party/freetype/src b/third_party/freetype/src
index 8eab511..ca76683 160000
--- a/third_party/freetype/src
+++ b/third_party/freetype/src
@@ -1 +1 @@
-Subproject commit 8eab511017a65026985523cab14aff07f1bb9746
+Subproject commit ca76683b781db5d06ef1a0e2cb62a767e7dbe626
diff --git a/third_party/libc++/src b/third_party/libc++/src
index 28d7125..d855d8b 160000
--- a/third_party/libc++/src
+++ b/third_party/libc++/src
@@ -1 +1 @@
-Subproject commit 28d7125795ff7da27512de569bb539e7ba44cb62
+Subproject commit d855d8bc2ef4a063c552236b57ed0b1ab2e6e0c1
diff --git a/third_party/libc++abi/src b/third_party/libc++abi/src
index c7c5649..8806fb8 160000
--- a/third_party/libc++abi/src
+++ b/third_party/libc++abi/src
@@ -1 +1 @@
-Subproject commit c7c5649e8badcb31e66f188f5cf7933f9a8f8287
+Subproject commit 8806fb8bb26e20206241ea2dfcee4fd2d4157b83
diff --git a/third_party/libvpx/BUILD.gn b/third_party/libvpx/BUILD.gn
index 5197549..5f4c4e66 100644
--- a/third_party/libvpx/BUILD.gn
+++ b/third_party/libvpx/BUILD.gn
@@ -559,4 +559,15 @@
       "//third_party/fuzztest:fuzztest_gtest_main",
     ]
   }
+
+  test("vp9_encoder_fuzz_test") {
+    sources = [ "tests/fuzzer/vp9_encoder_fuzz_test.cc" ]
+
+    enable_fuzztest = true
+
+    deps = [
+      ":libvpx",
+      "//third_party/fuzztest:fuzztest_gtest_main",
+    ]
+  }
 }
diff --git a/third_party/libvpx/tests/fuzzer/vp8_encoder_fuzz_test.cc b/third_party/libvpx/tests/fuzzer/vp8_encoder_fuzz_test.cc
index aa32ff8..be6ef70f 100644
--- a/third_party/libvpx/tests/fuzzer/vp8_encoder_fuzz_test.cc
+++ b/third_party/libvpx/tests/fuzzer/vp8_encoder_fuzz_test.cc
@@ -19,10 +19,6 @@
 #include "third_party/libvpx/source/libvpx/vpx/vpx_encoder.h"
 #include "third_party/libvpx/source/libvpx/vpx/vpx_image.h"
 
-// The libvpx API uses the unsigned long type.
-// NOLINTBEGIN(runtime/int)
-// NOLINTBEGIN(google-runtime-int)
-
 using fuzztest::Arbitrary;
 using fuzztest::ElementOf;
 using fuzztest::FlatMap;
@@ -43,7 +39,7 @@
   // scalabilityMode.
   vpx_rc_mode end_usage;   // Implies bitrateMode: constant, variable.
                            // Note: quantizer not implemented for VP8.
-  unsigned long deadline;  // Implies LatencyMode: quality, realtime.
+  vpx_enc_deadline_t deadline;  // Implies LatencyMode: quality, realtime.
   // TODO(wtc): contentHint.
 };
 
@@ -54,7 +50,7 @@
       /*height=*/Just(height),
       /*end_usage=*/ElementOf({VPX_VBR, VPX_CBR}),
       /*deadline=*/
-      ElementOf<unsigned long>({VPX_DL_GOOD_QUALITY, VPX_DL_REALTIME}));
+      ElementOf({VPX_DL_GOOD_QUALITY, VPX_DL_REALTIME}));
 }
 
 auto AnyConfigureWithMaxSize(unsigned int max_width, unsigned int max_height) {
@@ -65,7 +61,7 @@
       /*height=*/InRange(1u, max_height),
       /*end_usage=*/ElementOf({VPX_VBR, VPX_CBR}),
       /*deadline=*/
-      ElementOf<unsigned long>({VPX_DL_GOOD_QUALITY, VPX_DL_REALTIME}));
+      ElementOf({VPX_DL_GOOD_QUALITY, VPX_DL_REALTIME}));
 }
 
 // Represents a VideoEncoder::encode() method call.
@@ -107,8 +103,8 @@
 }
 
 void VP8EncodeArbitraryCallSequenceSucceeds(int speed,
-                                            CallSequence call_sequence) {
-  vpx_codec_iface_t* iface = vpx_codec_vp8_cx();
+                                            const CallSequence& call_sequence) {
+  vpx_codec_iface_t* const iface = vpx_codec_vp8_cx();
   vpx_codec_enc_cfg_t cfg;
   ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, /*usage=*/0),
             VPX_CODEC_OK);
@@ -128,7 +124,7 @@
 
   ASSERT_EQ(vpx_codec_control(&enc, VP8E_SET_CPUUSED, speed), VPX_CODEC_OK);
 
-  unsigned long deadline = call_sequence.initialize.deadline;
+  vpx_enc_deadline_t deadline = call_sequence.initialize.deadline;
   const vpx_codec_cx_pkt_t* pkt;
 
   int frame_index = 0;
@@ -146,21 +142,22 @@
       // Encode a frame.
       const Encode& encode = std::get<Encode>(call);
       // VP8 supports only one image format: 8-bit YUV 4:2:0.
-      vpx_image_t* image =
+      vpx_image_t* const image =
           vpx_img_alloc(nullptr, VPX_IMG_FMT_I420, cfg.g_w, cfg.g_h, 1);
       ASSERT_NE(image, nullptr);
 
       for (unsigned int i = 0; i < image->d_h; ++i) {
         memset(image->planes[0] + i * image->stride[0], 128, image->d_w);
       }
-      unsigned int uv_h = (image->d_h + 1) / 2;
-      unsigned int uv_w = (image->d_w + 1) / 2;
+      const unsigned int uv_h = (image->d_h + 1) / 2;
+      const unsigned int uv_w = (image->d_w + 1) / 2;
       for (unsigned int i = 0; i < uv_h; ++i) {
         memset(image->planes[1] + i * image->stride[1], 128, uv_w);
         memset(image->planes[2] + i * image->stride[2], 128, uv_w);
       }
 
-      vpx_enc_frame_flags_t flags = encode.key_frame ? VPX_EFLAG_FORCE_KF : 0;
+      const vpx_enc_frame_flags_t flags =
+          encode.key_frame ? VPX_EFLAG_FORCE_KF : 0;
       ASSERT_EQ(vpx_codec_encode(&enc, image, frame_index, 1, flags, deadline),
                 VPX_CODEC_OK);
       frame_index++;
@@ -182,6 +179,7 @@
     got_data = false;
     vpx_codec_iter_t iter = nullptr;
     while ((pkt = vpx_codec_get_cx_data(&enc, &iter)) != nullptr) {
+      ASSERT_EQ(pkt->kind, VPX_CODEC_CX_FRAME_PKT);
       got_data = true;
     }
   } while (got_data);
@@ -201,7 +199,7 @@
                        unsigned int width,
                        unsigned int height,
                        int num_frames) {
-  vpx_codec_iface_t* iface = vpx_codec_vp8_cx();
+  vpx_codec_iface_t* const iface = vpx_codec_vp8_cx();
   vpx_codec_enc_cfg_t cfg;
   ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, /*usage=*/0),
             VPX_CODEC_OK);
@@ -222,27 +220,28 @@
   ASSERT_EQ(vpx_codec_control(&enc, VP8E_SET_CPUUSED, speed), VPX_CODEC_OK);
 
   // VP8 supports only one image format: 8-bit YUV 4:2:0.
-  vpx_image_t* image =
+  vpx_image_t* const image =
       vpx_img_alloc(nullptr, VPX_IMG_FMT_I420, cfg.g_w, cfg.g_h, 1);
   ASSERT_NE(image, nullptr);
 
   for (unsigned int i = 0; i < image->d_h; ++i) {
     memset(image->planes[0] + i * image->stride[0], 128, image->d_w);
   }
-  unsigned int uv_h = (image->d_h + 1) / 2;
-  unsigned int uv_w = (image->d_w + 1) / 2;
+  const unsigned int uv_h = (image->d_h + 1) / 2;
+  const unsigned int uv_w = (image->d_w + 1) / 2;
   for (unsigned int i = 0; i < uv_h; ++i) {
     memset(image->planes[1] + i * image->stride[1], 128, uv_w);
     memset(image->planes[2] + i * image->stride[2], 128, uv_w);
   }
 
   // Encode frames.
-  const unsigned long deadline = VPX_DL_REALTIME;
+  const vpx_enc_deadline_t deadline = VPX_DL_REALTIME;
   const vpx_codec_cx_pkt_t* pkt;
   for (int i = 0; i < num_frames; ++i) {
     ASSERT_EQ(vpx_codec_encode(&enc, image, i, 1, 0, deadline), VPX_CODEC_OK);
     vpx_codec_iter_t iter = nullptr;
     while ((pkt = vpx_codec_get_cx_data(&enc, &iter)) != nullptr) {
+      ASSERT_EQ(pkt->kind, VPX_CODEC_CX_FRAME_PKT);
     }
   }
 
@@ -253,6 +252,7 @@
     got_data = false;
     vpx_codec_iter_t iter = nullptr;
     while ((pkt = vpx_codec_get_cx_data(&enc, &iter)) != nullptr) {
+      ASSERT_EQ(pkt->kind, VPX_CODEC_CX_FRAME_PKT);
       got_data = true;
     }
   } while (got_data);
@@ -269,6 +269,3 @@
                  /*width=*/InRange(1u, 1920u),
                  /*height=*/InRange(1u, 1080u),
                  /*num_frames=*/InRange(1, 10));
-
-// NOLINTEND(google-runtime-int)
-// NOLINTEND(runtime/int)
diff --git a/third_party/libvpx/tests/fuzzer/vp9_encoder_fuzz_test.cc b/third_party/libvpx/tests/fuzzer/vp9_encoder_fuzz_test.cc
new file mode 100644
index 0000000..f9dec41
--- /dev/null
+++ b/third_party/libvpx/tests/fuzzer/vp9_encoder_fuzz_test.cc
@@ -0,0 +1,271 @@
+/*
+ *  Copyright (c) 2023 The WebM project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <cstring>
+#include <variant>
+#include <vector>
+
+#include "third_party/fuzztest/src/fuzztest/fuzztest.h"
+#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
+#include "third_party/libvpx/source/libvpx/vpx/vp8cx.h"
+#include "third_party/libvpx/source/libvpx/vpx/vpx_codec.h"
+#include "third_party/libvpx/source/libvpx/vpx/vpx_encoder.h"
+#include "third_party/libvpx/source/libvpx/vpx/vpx_image.h"
+
+using fuzztest::Arbitrary;
+using fuzztest::ElementOf;
+using fuzztest::FlatMap;
+using fuzztest::InRange;
+using fuzztest::Just;
+using fuzztest::StructOf;
+using fuzztest::VariantOf;
+using fuzztest::VectorOf;
+
+// Represents a VideoEncoder::configure() method call.
+// Parameters:
+//   VideoEncoderConfig config
+struct Configure {
+  unsigned int threads;  // Not part of VideoEncoderConfig
+  unsigned int width;    // Nonzero
+  unsigned int height;   // Nonzero
+  // TODO(wtc): displayWidth, displayHeight, bitrate, framerate,
+  // scalabilityMode.
+  vpx_rc_mode end_usage;        // Implies bitrateMode: constant, variable.
+                                // TODO(wtc): quantizer.
+  vpx_enc_deadline_t deadline;  // Implies LatencyMode: quality, realtime.
+  // TODO(wtc): contentHint.
+};
+
+auto AnyConfigureWithSize(unsigned int width, unsigned int height) {
+  return StructOf<Configure>(
+      // Chrome's WebCodecs uses at most 16 threads.
+      /*threads=*/InRange(0u, 16u), /*width=*/Just(width),
+      /*height=*/Just(height),
+      /*end_usage=*/ElementOf({VPX_VBR, VPX_CBR}),
+      /*deadline=*/
+      ElementOf({VPX_DL_GOOD_QUALITY, VPX_DL_REALTIME}));
+}
+
+auto AnyConfigureWithMaxSize(unsigned int max_width, unsigned int max_height) {
+  return StructOf<Configure>(
+      // Chrome's WebCodecs uses at most 16 threads.
+      /*threads=*/InRange(0u, 16u),
+      /*width=*/InRange(1u, max_width),
+      /*height=*/InRange(1u, max_height),
+      /*end_usage=*/ElementOf({VPX_VBR, VPX_CBR}),
+      /*deadline=*/
+      ElementOf({VPX_DL_GOOD_QUALITY, VPX_DL_REALTIME}));
+}
+
+// Represents a VideoEncoder::encode() method call.
+// Parameters:
+//   VideoFrame frame
+//   optional VideoEncoderEncodeOptions options = {}
+struct Encode {
+  bool key_frame;
+  // TODO(wtc): quantizer.
+};
+
+auto AnyEncode() {
+  return StructOf<Encode>(Arbitrary<bool>());
+}
+
+using MethodCall = std::variant<Configure, Encode>;
+
+auto AnyMethodCallWithMaxSize(unsigned int max_width, unsigned int max_height) {
+  return VariantOf(AnyConfigureWithMaxSize(max_width, max_height), AnyEncode());
+}
+
+struct CallSequence {
+  Configure initialize;
+  std::vector<MethodCall> method_calls;
+};
+
+auto AnyCallSequenceWithMaxSize(unsigned int max_width,
+                                unsigned int max_height) {
+  return StructOf<CallSequence>(
+      /*initialize=*/AnyConfigureWithSize(max_width, max_height),
+      /*method_calls=*/VectorOf(AnyMethodCallWithMaxSize(max_width, max_height))
+          .WithMaxSize(20));
+}
+
+auto AnyCallSequence() {
+  return FlatMap(AnyCallSequenceWithMaxSize,
+                 /*max_width=*/InRange(1u, 1920u),
+                 /*max_height=*/InRange(1u, 1080u));
+}
+
+void VP9EncodeArbitraryCallSequenceSucceeds(int speed,
+                                            const CallSequence& call_sequence) {
+  vpx_codec_iface_t* const iface = vpx_codec_vp9_cx();
+  vpx_codec_enc_cfg_t cfg;
+  ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, /*usage=*/0),
+            VPX_CODEC_OK);
+  cfg.g_threads = call_sequence.initialize.threads;
+  cfg.g_w = call_sequence.initialize.width;
+  cfg.g_h = call_sequence.initialize.height;
+  cfg.g_timebase.num = 1;
+  cfg.g_timebase.den = 1000 * 1000;  // microseconds
+  cfg.g_pass = VPX_RC_ONE_PASS;
+  cfg.g_lag_in_frames = 0;
+  cfg.rc_end_usage = call_sequence.initialize.end_usage;
+  cfg.rc_min_quantizer = 2;
+  cfg.rc_max_quantizer = 58;
+
+  vpx_codec_ctx_t enc;
+  ASSERT_EQ(vpx_codec_enc_init(&enc, iface, &cfg, 0), VPX_CODEC_OK);
+
+  ASSERT_EQ(vpx_codec_control(&enc, VP8E_SET_CPUUSED, speed), VPX_CODEC_OK);
+
+  vpx_enc_deadline_t deadline = call_sequence.initialize.deadline;
+  const vpx_codec_cx_pkt_t* pkt;
+
+  int frame_index = 0;
+  for (const auto& call : call_sequence.method_calls) {
+    if (std::holds_alternative<Configure>(call)) {
+      const Configure& configure = std::get<Configure>(call);
+      cfg.g_threads = configure.threads;
+      cfg.g_w = configure.width;
+      cfg.g_h = configure.height;
+      cfg.rc_end_usage = configure.end_usage;
+      ASSERT_EQ(vpx_codec_enc_config_set(&enc, &cfg), VPX_CODEC_OK)
+          << vpx_codec_error_detail(&enc);
+      deadline = configure.deadline;
+    } else {
+      // Encode a frame.
+      const Encode& encode = std::get<Encode>(call);
+      // TODO(wtc): Support high bit depths and other YUV formats.
+      vpx_image_t* const image =
+          vpx_img_alloc(nullptr, VPX_IMG_FMT_I420, cfg.g_w, cfg.g_h, 1);
+      ASSERT_NE(image, nullptr);
+
+      for (unsigned int i = 0; i < image->d_h; ++i) {
+        memset(image->planes[0] + i * image->stride[0], 128, image->d_w);
+      }
+      const unsigned int uv_h = (image->d_h + 1) / 2;
+      const unsigned int uv_w = (image->d_w + 1) / 2;
+      for (unsigned int i = 0; i < uv_h; ++i) {
+        memset(image->planes[1] + i * image->stride[1], 128, uv_w);
+        memset(image->planes[2] + i * image->stride[2], 128, uv_w);
+      }
+
+      const vpx_enc_frame_flags_t flags =
+          encode.key_frame ? VPX_EFLAG_FORCE_KF : 0;
+      ASSERT_EQ(vpx_codec_encode(&enc, image, frame_index, 1, flags, deadline),
+                VPX_CODEC_OK);
+      frame_index++;
+      vpx_codec_iter_t iter = nullptr;
+      while ((pkt = vpx_codec_get_cx_data(&enc, &iter)) != nullptr) {
+        ASSERT_EQ(pkt->kind, VPX_CODEC_CX_FRAME_PKT);
+        if (encode.key_frame) {
+          ASSERT_EQ(pkt->data.frame.flags & VPX_FRAME_IS_KEY, VPX_FRAME_IS_KEY);
+        }
+      }
+      vpx_img_free(image);
+    }
+  }
+
+  // Flush the encoder.
+  bool got_data;
+  do {
+    ASSERT_EQ(vpx_codec_encode(&enc, nullptr, 0, 1, 0, deadline), VPX_CODEC_OK);
+    got_data = false;
+    vpx_codec_iter_t iter = nullptr;
+    while ((pkt = vpx_codec_get_cx_data(&enc, &iter)) != nullptr) {
+      ASSERT_EQ(pkt->kind, VPX_CODEC_CX_FRAME_PKT);
+      got_data = true;
+    }
+  } while (got_data);
+
+  ASSERT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK);
+}
+
+FUZZ_TEST(VP9EncodeFuzzTest, VP9EncodeArbitraryCallSequenceSucceeds)
+    .WithDomains(/*speed=*/InRange(-9, 9),
+                 /*call_sequence=*/AnyCallSequence());
+
+// speed: range -9..9
+// end_usage: Rate control mode
+void VP9EncodeSucceeds(unsigned int threads,
+                       int speed,
+                       vpx_rc_mode end_usage,
+                       unsigned int width,
+                       unsigned int height,
+                       int num_frames) {
+  vpx_codec_iface_t* const iface = vpx_codec_vp9_cx();
+  vpx_codec_enc_cfg_t cfg;
+  ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, /*usage=*/0),
+            VPX_CODEC_OK);
+  cfg.g_threads = threads;
+  cfg.g_w = width;
+  cfg.g_h = height;
+  cfg.g_timebase.num = 1;
+  cfg.g_timebase.den = 1000 * 1000;  // microseconds
+  cfg.g_pass = VPX_RC_ONE_PASS;
+  cfg.g_lag_in_frames = 0;
+  cfg.rc_end_usage = end_usage;
+  cfg.rc_min_quantizer = 2;
+  cfg.rc_max_quantizer = 58;
+
+  vpx_codec_ctx_t enc;
+  ASSERT_EQ(vpx_codec_enc_init(&enc, iface, &cfg, 0), VPX_CODEC_OK);
+
+  ASSERT_EQ(vpx_codec_control(&enc, VP8E_SET_CPUUSED, speed), VPX_CODEC_OK);
+
+  // TODO(wtc): Support high bit depths and other YUV formats.
+  vpx_image_t* const image =
+      vpx_img_alloc(nullptr, VPX_IMG_FMT_I420, cfg.g_w, cfg.g_h, 1);
+  ASSERT_NE(image, nullptr);
+
+  for (unsigned int i = 0; i < image->d_h; ++i) {
+    memset(image->planes[0] + i * image->stride[0], 128, image->d_w);
+  }
+  const unsigned int uv_h = (image->d_h + 1) / 2;
+  const unsigned int uv_w = (image->d_w + 1) / 2;
+  for (unsigned int i = 0; i < uv_h; ++i) {
+    memset(image->planes[1] + i * image->stride[1], 128, uv_w);
+    memset(image->planes[2] + i * image->stride[2], 128, uv_w);
+  }
+
+  // Encode frames.
+  const vpx_enc_deadline_t deadline = VPX_DL_REALTIME;
+  const vpx_codec_cx_pkt_t* pkt;
+  for (int i = 0; i < num_frames; ++i) {
+    ASSERT_EQ(vpx_codec_encode(&enc, image, i, 1, 0, deadline), VPX_CODEC_OK);
+    vpx_codec_iter_t iter = nullptr;
+    while ((pkt = vpx_codec_get_cx_data(&enc, &iter)) != nullptr) {
+      ASSERT_EQ(pkt->kind, VPX_CODEC_CX_FRAME_PKT);
+    }
+  }
+
+  // Flush the encoder.
+  bool got_data;
+  do {
+    ASSERT_EQ(vpx_codec_encode(&enc, nullptr, 0, 1, 0, deadline), VPX_CODEC_OK);
+    got_data = false;
+    vpx_codec_iter_t iter = nullptr;
+    while ((pkt = vpx_codec_get_cx_data(&enc, &iter)) != nullptr) {
+      ASSERT_EQ(pkt->kind, VPX_CODEC_CX_FRAME_PKT);
+      got_data = true;
+    }
+  } while (got_data);
+
+  vpx_img_free(image);
+  ASSERT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK);
+}
+
+// Chrome's WebCodecs uses at most 16 threads.
+FUZZ_TEST(VP9EncodeFuzzTest, VP9EncodeSucceeds)
+    .WithDomains(/*threads=*/InRange(0u, 16u),
+                 /*speed=*/InRange(-9, 9),
+                 /*end_usage=*/ElementOf({VPX_VBR, VPX_CBR}),
+                 /*width=*/InRange(1u, 1920u),
+                 /*height=*/InRange(1u, 1080u),
+                 /*num_frames=*/InRange(1, 10));
diff --git a/third_party/perfetto b/third_party/perfetto
index 84bb6bc..819068d 160000
--- a/third_party/perfetto
+++ b/third_party/perfetto
@@ -1 +1 @@
-Subproject commit 84bb6bced2420d2e7bd880cbf30b348448fa95d4
+Subproject commit 819068d7e83a09200ee0b3a43fe44d90465cca5e
diff --git a/third_party/webrtc b/third_party/webrtc
index acdc89d6..2b311ea 160000
--- a/third_party/webrtc
+++ b/third_party/webrtc
@@ -1 +1 @@
-Subproject commit acdc89d65328911b4e98afe0757028eca162cbb3
+Subproject commit 2b311ea96a10b87cec66e2626ecadfa08dd868b1
diff --git a/third_party/zlib/deflate.h b/third_party/zlib/deflate.h
index 654d094..eb7f0724 100644
--- a/third_party/zlib/deflate.h
+++ b/third_party/zlib/deflate.h
@@ -25,7 +25,7 @@
 
 /* define LIT_MEM to slightly increase the speed of deflate (order 1% to 2%) at
    the cost of a larger memory footprint */
-/* #define LIT_MEM */
+#define LIT_MEM
 
 /* ===========================================================================
  * Internal compression state.
diff --git a/tools/fuchsia/OWNERS b/tools/fuchsia/OWNERS
index 6a0c8dc..6ee0025 100644
--- a/tools/fuchsia/OWNERS
+++ b/tools/fuchsia/OWNERS
@@ -1,4 +1,3 @@
-chonggu@google.com
 zijiehe@google.com
 
 file://build/fuchsia/OWNERS
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
index 960c936..da65719 100644
--- a/tools/gritsettings/resource_ids.spec
+++ b/tools/gritsettings/resource_ids.spec
@@ -1130,7 +1130,7 @@
     "messages": [7500],
   },
   "<(SHARED_INTERMEDIATE_DIR)/ash/webui/shimless_rma/resources/resources.grd": {
-    "META": {"sizes": {"includes": [80],}},
+    "META": {"sizes": {"includes": [100],}},
     "includes": [7520],
   },
   "ash/keyboard/ui/keyboard_resources.grd": {
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 39d884a4..1ce18f05 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -3356,6 +3356,12 @@
   <int value="23"
       label="No frame currently has focus. This case is caught for safety
              because it might be reachable due to race conditions."/>
+  <int value="24"
+      label="The sub-popup was closed, e.g. because the mouse was moved to a
+             different suggestion in the parent popup."/>
+  <int value="25"
+      label="The user edited the field. Currently applied only to Compose
+             suggestions."/>
 </enum>
 
 <enum name="AutofillPredictionsComparisonResult">
@@ -5405,6 +5411,8 @@
   <int value="271" label="UpdateCreditCardCvc: Failure"/>
   <int value="272" label="ClearLocalCvcs: Success"/>
   <int value="273" label="ClearLocalCvcs: Failure"/>
+  <int value="274" label="UpdateServerIbanMetadata: Success"/>
+  <int value="275" label="UpdateServerIbanMetadata: Failure"/>
 </enum>
 
 <enum name="AutomaticLazyFrameLoadReason">
@@ -28964,7 +28972,6 @@
   <int value="-1961755742" label="LightweightReactions:enabled"/>
   <int value="-1961648833" label="show_summary"/>
   <int value="-1961102654" label="WebNotesStylize:enabled"/>
-  <int value="-1961071650" label="InterestFeedV2Autoplay:disabled"/>
   <int value="-1961062505" label="VrBrowsingInCustomTab:disabled"/>
   <int value="-1960567385" label="KeepPrefetchedContentSuggestions:enabled"/>
   <int value="-1960250727" label="DefaultANGLEVulkan:disabled"/>
@@ -29406,7 +29413,6 @@
   <int value="-1755714804" label="FeedCloseRefresh:enabled"/>
   <int value="-1755301960" label="ClearOldBrowsingData:enabled"/>
   <int value="-1754262889" label="RemoteCopyPersistentNotification:enabled"/>
-  <int value="-1753458842" label="OfflinePagesLivePageSharing:disabled"/>
   <int value="-1752853388"
       label="OmniboxUIExperimentElideToRegistrableDomain:enabled"/>
   <int value="-1752118355" label="DesktopDetailedLanguageSettings:enabled"/>
@@ -30244,6 +30250,7 @@
   <int value="-1367447724"
       label="IncognitoClearBrowsingDataDialogForDesktop:disabled"/>
   <int value="-1366114365" label="BluetoothAdvertisementMonitoring:disabled"/>
+  <int value="-1365859601" label="CCTPageInsightsHubBetterScroll:disabled"/>
   <int value="-1365795470"
       label="ServiceWorkerImportedScriptUpdateCheck:disabled"/>
   <int value="-1365503870" label="enable-simplified-fullscreen-ui"/>
@@ -31343,7 +31350,6 @@
   <int value="-844786349" label="ClipboardHistoryNudgeSessionReset:enabled"/>
   <int value="-844537521" label="HttpFormWarning:disabled"/>
   <int value="-844381918" label="ArcNativeBridgeExperiment:disabled"/>
-  <int value="-844067635" label="InterestFeedV2Autoplay:enabled"/>
   <int value="-843496368" label="AutofillRejectCompanyBirthyear:disabled"/>
   <int value="-842798026" label="LinkCrossDeviceInternals:disabled"/>
   <int value="-842597982" label="ShelfPalmRejectionTouchArea:disabled"/>
@@ -32072,6 +32078,7 @@
   <int value="-502813092" label="SmdsSupport:enabled"/>
   <int value="-502004335" label="OobeHidDetectionRevamp:enabled"/>
   <int value="-501853726" label="MultiZoneRgbKeyboard:enabled"/>
+  <int value="-500367371" label="CCTPageInsightsHubBetterScroll:enabled"/>
   <int value="-499723386" label="EnableFilesAppCopyImage:disabled"/>
   <int value="-499186481"
       label="OmniboxGroupSuggestionsBySearchVsUrl:disabled"/>
@@ -33054,7 +33061,6 @@
   <int value="-36007541"
       label="DataRetentionPoliciesDisableSyncTypesNeeded:enabled"/>
   <int value="-35745997" label="TabSearch:enabled"/>
-  <int value="-35528548" label="LensImageFormatOptimizations:disabled"/>
   <int value="-35388407" label="AshNewSystemMenu:disabled"/>
   <int value="-35256214" label="InterestFeedNoticeCardAutoDismiss:enabled"/>
   <int value="-35002051" label="DefaultBucketUsesRelaxedDurability:enabled"/>
@@ -35627,7 +35633,6 @@
   <int value="1198011819" label="TimeOfDayWallpaperForcedAutoSchedule:enabled"/>
   <int value="1198019369" label="PlatformKeysAesEncryption:enabled"/>
   <int value="1198604672" label="DiscardExceptionsImprovements:disabled"/>
-  <int value="1198839129" label="OfflinePagesLivePageSharing:enabled"/>
   <int value="1199200896" label="FileTransferEnterpriseConnectorUI:enabled"/>
   <int value="1199276782" label="HighEfficiencyMultistateMode:enabled"/>
   <int value="1199381550"
@@ -37149,7 +37154,6 @@
   <int value="1895993853" label="NtpRealboxRoundedCorners:enabled"/>
   <int value="1896456311" label="enable-password-save-in-page-navigation"/>
   <int value="1896527497" label="ImmersiveUiMode:enabled"/>
-  <int value="1897117967" label="LensImageFormatOptimizations:enabled"/>
   <int value="1898231011" label="enable-native-notifications"/>
   <int value="1898286738" label="EnableRFC8925:disabled"/>
   <int value="1899111954" label="WebRtcMetronomeTaskQueue:disabled"/>
@@ -41874,20 +41878,6 @@
              OriginAgentCluster-by-default)"/>
 </enum>
 
-<enum name="OriginTrialTokenStatus">
-  <int value="0" label="Success"/>
-  <int value="1" label="NotSupported"/>
-  <int value="2" label="Insecure"/>
-  <int value="3" label="Expired"/>
-  <int value="4" label="WrongOrigin"/>
-  <int value="5" label="InvalidSignature"/>
-  <int value="6" label="Malformed"/>
-  <int value="7" label="WrongVersion"/>
-  <int value="8" label="FeatureDisabled"/>
-  <int value="9" label="TokenDisabled"/>
-  <int value="10" label="FeatureDisabledForUser"/>
-</enum>
-
 <enum name="OsSetting">
   <int value="0" label="Configure Ethernet"/>
   <int value="1" label="Ethernet: Automatically Configure IP Address"/>
@@ -47691,6 +47681,10 @@
       label="Model execution score for default model is obtained from
              database"/>
   <int value="28" label="Score from database for default model is not ready"/>
+  <int value="29"
+      label="Cached result is unavailable, execute the model ondemand."/>
+  <int value="30"
+      label="Ondemand model execution failed, returned cached results."/>
 </enum>
 
 <enum name="SelectedTheme">
@@ -51190,21 +51184,6 @@
   <int value="505" label="505: HTTP Version Not Supported"/>
 </enum>
 
-<enum name="VerifyDidCommitParamsDifference">
-  <summary>
-    The params that differ when comparing browser- and renderer-calculated
-    DidCommitProvisionalLoadParams.
-  </summary>
-  <int value="0" label="intended_as_new_entry"/>
-  <int value="1" label="method"/>
-  <int value="2" label="url_is_unreachable"/>
-  <int value="3" label="base_url"/>
-  <int value="4" label="post_id"/>
-  <int value="5" label="is_overriding_user_agent"/>
-  <int value="6" label="http_status_code"/>
-  <int value="7" label="should_update_history"/>
-</enum>
-
 <enum name="VertexOpacityUsage">
   <int value="0" label="None">
     Vertex opacity is not used. Default value of 1f.
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml
index 7fe8fbc..a40a653 100644
--- a/tools/metrics/histograms/metadata/android/histograms.xml
+++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -5552,7 +5552,7 @@
 </histogram>
 
 <histogram name="Android.WebView.Startup.CreationTime.Stage1.FactoryInit"
-    units="ms" expires_after="2024-05-05">
+    units="ms" expires_after="2024-12-31">
   <owner>torne@chromium.org</owner>
   <owner>src/android_webview/OWNERS</owner>
   <summary>
@@ -5562,7 +5562,7 @@
 </histogram>
 
 <histogram name="Android.WebView.Startup.CreationTime.Stage2.ProviderInit.Cold"
-    units="ms" expires_after="2023-12-31">
+    units="ms" expires_after="2024-12-31">
   <owner>torne@chromium.org</owner>
   <owner>src/android_webview/OWNERS</owner>
   <summary>
@@ -5574,7 +5574,7 @@
 </histogram>
 
 <histogram name="Android.WebView.Startup.CreationTime.Stage2.ProviderInit.Warm"
-    units="ms" expires_after="2024-05-05">
+    units="ms" expires_after="2024-12-31">
   <owner>torne@chromium.org</owner>
   <owner>src/android_webview/OWNERS</owner>
   <summary>
@@ -5586,14 +5586,14 @@
 </histogram>
 
 <histogram name="Android.WebView.Startup.CreationTime.StartChromiumLocked"
-    units="ms" expires_after="2023-12-31">
+    units="ms" expires_after="2024-12-31">
   <owner>torne@chromium.org</owner>
   <owner>src/android_webview/OWNERS</owner>
   <summary>How long it takes to run startChromiumLocked.</summary>
 </histogram>
 
 <histogram name="Android.WebView.Startup.CreationTime.TotalFactoryInitTime"
-    units="ms" expires_after="2023-12-31">
+    units="ms" expires_after="2024-12-31">
   <owner>torne@chromium.org</owner>
   <owner>src/android_webview/OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index 114ca323..992d036 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -3774,7 +3774,7 @@
 </histogram>
 
 <histogram name="Ash.InteractiveWindowResize.Lacros.TimeToPresent" units="ms"
-    expires_after="2024-01-29">
+    expires_after="2024-12-18">
   <owner>xiyuan@chromium.org</owner>
   <owner>oshima@chromium.org</owner>
   <summary>
@@ -3785,7 +3785,7 @@
 </histogram>
 
 <histogram name="Ash.InteractiveWindowResize.Lacros.TimeToPresent.MaxLatency"
-    units="ms" expires_after="2024-01-29">
+    units="ms" expires_after="2024-12-18">
   <owner>xiyuan@chromium.org</owner>
   <owner>oshima@chromium.org</owner>
   <summary>
@@ -3795,7 +3795,7 @@
 </histogram>
 
 <histogram name="Ash.InteractiveWindowResize.TimeToPresent" units="ms"
-    expires_after="2024-04-16">
+    expires_after="2024-12-18">
   <owner>xiyuan@chromium.org</owner>
   <owner>oshima@chromium.org</owner>
   <summary>
@@ -3806,7 +3806,7 @@
 </histogram>
 
 <histogram name="Ash.InteractiveWindowResize.TimeToPresent.MaxLatency"
-    units="ms" expires_after="2024-04-16">
+    units="ms" expires_after="2024-12-18">
   <owner>xiyuan@chromium.org</owner>
   <owner>oshima@chromium.org</owner>
   <summary>
@@ -4653,7 +4653,7 @@
 </histogram>
 
 <histogram name="Ash.NotifierFramework.Nudge.ShownCount"
-    enum="NudgeCatalogName" expires_after="2024-05-19">
+    enum="NudgeCatalogName" expires_after="2025-01-15">
   <owner>kradtke@chromium.org</owner>
   <owner>cros-status-area-eng@google.com</owner>
   <summary>
@@ -4663,7 +4663,7 @@
 </histogram>
 
 <histogram name="Ash.NotifierFramework.Nudge.TimeToAction.{TimeRange}"
-    enum="NudgeCatalogName" expires_after="2024-05-19">
+    enum="NudgeCatalogName" expires_after="2025-01-15">
   <owner>kradtke@google.com</owner>
   <owner>cros-status-area-eng@google.com</owner>
   <summary>
@@ -4680,7 +4680,7 @@
 </histogram>
 
 <histogram name="Ash.NotifierFramework.Nudge.{PrimaryOrSecondary}ButtonPressed"
-    enum="NudgeCatalogName" expires_after="2024-11-01">
+    enum="NudgeCatalogName" expires_after="2025-01-15">
   <owner>kradtke@google.com</owner>
   <owner>cros-status-area-eng@google.com</owner>
   <summary>
@@ -4694,7 +4694,7 @@
 </histogram>
 
 <histogram name="Ash.NotifierFramework.Toast.Dismissed.{TimeRange}"
-    enum="ToastCatalogName" expires_after="2024-01-15">
+    enum="ToastCatalogName" expires_after="2025-01-15">
   <owner>kradtke@google.com</owner>
   <owner>cros-status-area-eng@google.com</owner>
   <summary>
@@ -4710,7 +4710,7 @@
 </histogram>
 
 <histogram name="Ash.NotifierFramework.Toast.ShownCount"
-    enum="ToastCatalogName" expires_after="2024-05-19">
+    enum="ToastCatalogName" expires_after="2025-05-19">
   <owner>kradtke@chromium.org</owner>
   <owner>cros-status-area-eng@google.com</owner>
   <summary>
@@ -4720,7 +4720,7 @@
 </histogram>
 
 <histogram name="Ash.NotifierFramework.Toast.TimeInQueue" units="seconds"
-    expires_after="2024-05-19">
+    expires_after="2025-05-19">
   <owner>kradtke@chromium.org</owner>
   <owner>cros-status-area-eng@google.com</owner>
   <summary>
@@ -4730,7 +4730,7 @@
 
 <histogram
     name="Ash.NotifierFramework.{UnpinnedOrPinned}SystemNotification.Added"
-    enum="NotificationCatalogName" expires_after="2024-05-19">
+    enum="NotificationCatalogName" expires_after="2025-01-15">
   <owner>kradtke@google.com</owner>
   <owner>cros-status-area-eng@google.com</owner>
   <summary>
@@ -4746,7 +4746,7 @@
 
 <histogram
     name="Ash.NotifierFramework.{UnpinnedOrPinned}SystemNotification.ClickedActionButton.{ButtonIndex}"
-    enum="NotificationCatalogName" expires_after="2024-05-26">
+    enum="NotificationCatalogName" expires_after="2025-01-15">
   <owner>kradtke@google.com</owner>
   <owner>cros-status-area-eng@google.com</owner>
   <summary>
@@ -4767,7 +4767,7 @@
 
 <histogram
     name="Ash.NotifierFramework.{UnpinnedOrPinned}SystemNotification.Popup.Dismissed.{TimeRange}"
-    enum="NotificationCatalogName" expires_after="2024-05-19">
+    enum="NotificationCatalogName" expires_after="2025-01-15">
   <owner>kradtke@google.com</owner>
   <owner>cros-status-area-eng@google.com</owner>
   <summary>
@@ -4790,7 +4790,7 @@
 
 <histogram
     name="Ash.NotifierFramework.{UnpinnedOrPinned}SystemNotification.Popup.ShownCount"
-    enum="NotificationCatalogName" expires_after="2024-05-19">
+    enum="NotificationCatalogName" expires_after="2025-01-15">
   <owner>kradtke@google.com</owner>
   <owner>cros-status-area-eng@google.com</owner>
   <summary>
@@ -4805,7 +4805,7 @@
 
 <histogram
     name="Ash.NotifierFramework.{UnpinnedOrPinned}SystemNotification.Popup.UserJourneyTime"
-    units="seconds" expires_after="2024-01-15">
+    units="seconds" expires_after="2025-01-15">
   <owner>kradtke@google.com</owner>
   <owner>cros-status-area-eng@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/autofill/histograms.xml b/tools/metrics/histograms/metadata/autofill/histograms.xml
index 16f6d81e..84b2edb8 100644
--- a/tools/metrics/histograms/metadata/autofill/histograms.xml
+++ b/tools/metrics/histograms/metadata/autofill/histograms.xml
@@ -443,6 +443,11 @@
   <variant name=".WithOnlyServerData" summary="only server autofill data"/>
 </variants>
 
+<variants name="IbanRecordType">
+  <variant name="Local" summary="Local IBAN"/>
+  <variant name="Server" summary="Server IBAN"/>
+</variants>
+
 <variants name="IbanTypeToBeSaved">
   <variant name=".Local" summary="Local IBAN save"/>
   <variant name=".Upload" summary="Server IBAN save"/>
@@ -1580,7 +1585,7 @@
   </summary>
 </histogram>
 
-<histogram name="Autofill.DaysSinceLastUse.StoredIban{IbanTypeToBeSaved}"
+<histogram name="Autofill.DaysSinceLastUse.StoredIban.{IbanRecordType}"
     units="days" expires_after="2024-07-01">
   <owner>qihuizhao@google.com</owner>
   <owner>jsaul@google.com</owner>
@@ -1590,7 +1595,7 @@
     given Chrome Profile was last used. This is logged for each Autofill IBAN
     once per Chrome User Profile load.
   </summary>
-  <token key="IbanTypeToBeSaved" variants="IbanTypeToBeSaved"/>
+  <token key="IbanRecordType" variants="IbanRecordType"/>
 </histogram>
 
 <histogram name="Autofill.DaysSinceLastUse.StoredProfile.{Category}"
diff --git a/tools/metrics/histograms/metadata/chromeos_settings/enums.xml b/tools/metrics/histograms/metadata/chromeos_settings/enums.xml
index 4b3c1bda..9a0dce41 100644
--- a/tools/metrics/histograms/metadata/chromeos_settings/enums.xml
+++ b/tools/metrics/histograms/metadata/chromeos_settings/enums.xml
@@ -32,6 +32,13 @@
   <int value="2" label="Scaling"/>
   <int value="3" label="Orientation"/>
   <int value="4" label="Overscan"/>
+  <int value="5" label="NightLight"/>
+  <int value="6" label="NightLightSchedule"/>
+</enum>
+
+<enum name="DisplayType">
+  <int value="0" label="ExternalDisplay"/>
+  <int value="1" label="InternalDisplay"/>
 </enum>
 
 </enums>
diff --git a/tools/metrics/histograms/metadata/chromeos_settings/histograms.xml b/tools/metrics/histograms/metadata/chromeos_settings/histograms.xml
index adedd94..536a768 100644
--- a/tools/metrics/histograms/metadata/chromeos_settings/histograms.xml
+++ b/tools/metrics/histograms/metadata/chromeos_settings/histograms.xml
@@ -175,6 +175,18 @@
   </summary>
 </histogram>
 
+<histogram name="ChromeOS.Settings.Display.NewDisplayConnected"
+    enum="DisplayType" expires_after="2024-06-28">
+  <owner>zhangwenyu@google.com</owner>
+  <owner>cros-peripherals@google.com</owner>
+  <summary>
+    Records when an internal/external display is connected for the first time.
+    This is part of the metrics aiming to measure how well system provided
+    default display settings work, by calculating the percentage of users who
+    change the default settings after a display is connected for the first time.
+  </summary>
+</histogram>
+
 <histogram name="ChromeOS.Settings.Display.{DisplayType}"
     enum="DisplaySettingsType" expires_after="2024-06-28">
   <owner>zhangwenyu@google.com</owner>
@@ -189,6 +201,26 @@
   </token>
 </histogram>
 
+<histogram
+    name="ChromeOS.Settings.Display.{DisplayType}.UserOverrideDisplayDefaultSettingsTimeElapsed.{DisplaySettings}"
+    units="minutes" expires_after="2024-06-28">
+  <owner>zhangwenyu@google.com</owner>
+  <owner>cros-peripherals@google.com</owner>
+  <summary>
+    Records the time elapsed when user overrides the {DisplayType} display
+    {DisplaySettings} provided by default. Only record when an {DisplayType}
+    display is connected for the first time.
+  </summary>
+  <token key="DisplayType">
+    <variant name="External" summary="external"/>
+    <variant name="Internal" summary="internal"/>
+  </token>
+  <token key="DisplaySettings">
+    <variant name="Resolution" summary="resolution"/>
+    <variant name="Scaling" summary="scaling"/>
+  </token>
+</histogram>
+
 <histogram name="ChromeOS.Settings.Inputs.ShortcutReminderDismissed"
     enum="SettingsInputsShortcutReminderState" expires_after="2023-11-12">
   <owner>mlcui@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/event/enums.xml b/tools/metrics/histograms/metadata/event/enums.xml
index ee487ad1..84141fb 100644
--- a/tools/metrics/histograms/metadata/event/enums.xml
+++ b/tools/metrics/histograms/metadata/event/enums.xml
@@ -243,25 +243,6 @@
              is system apps and dialogs"/>
 </enum>
 
-<enum name="EventPageShowPersisted">
-  <int value="0" label="No in renderer"/>
-  <int value="1" label="Yes in renderer"/>
-  <int value="2" label="Yes in browser"/>
-  <int value="3"
-      label="Yes in browser
-             BackForwardCacheImpl::WillCommitNavigationToCachedEntry"/>
-  <int value="4"
-      label="Yes in browser BackForwardCacheImpl::RestoreEntry attempt"/>
-  <int value="5"
-      label="Yes in browser BackForwardCacheImpl::RestoreEntry succeed"/>
-  <int value="6" label="Yes in browser RenderFrameHostManager::CommitPending"/>
-  <int value="7" label="Yes in browser seen in renderer"/>
-  <int value="8" label="Yes in browser seen in renderer with Page"/>
-  <int value="9" label="Yes in browser seen in ACK to browser"/>
-  <int value="10" label="Yes in browser while disconnected"/>
-  <int value="11" label="Yes in browser while RenderView was not live"/>
-</enum>
-
 <enum name="EventResultType">
   <int value="0" label="Passive"/>
   <int value="1" label="Uncancelable"/>
diff --git a/tools/metrics/histograms/metadata/event/histograms.xml b/tools/metrics/histograms/metadata/event/histograms.xml
index 2f0a4173..79dbc27 100644
--- a/tools/metrics/histograms/metadata/event/histograms.xml
+++ b/tools/metrics/histograms/metadata/event/histograms.xml
@@ -844,52 +844,6 @@
   </token>
 </histogram>
 
-<histogram name="Event.PageShow.Persisted" enum="EventPageShowPersisted"
-    expires_after="2023-03-26">
-  <owner>hajimehoshi@chromium.org</owner>
-  <owner>fergal@chromium.org</owner>
-  <summary>
-    Records whether the pageshow event had its persisted flag set in renderer or
-    browser. This flag is on if and only if the page is restored from
-    back-forward cache. This flag is off e.g. during the page load. This is
-    recorded when pageshow event fires on a main frame in renderer, or when
-    browser triggers this event on a main frame. This was a boolean on M95 and
-    before, is extended to an enum EventPageShoerPersisted as of M96.
-  </summary>
-</histogram>
-
-<histogram name="Event.PageShow.Persisted.Termination.Status" units="status"
-    expires_after="2022-12-25">
-  <owner>hajimehoshi@chromium.org</owner>
-  <owner>fergal@chromium.org</owner>
-  <summary>
-    When we send a PageLifecycleState update that should trigger a pageshow
-    event with its persisted flag set and then the renderer exits, this records
-    the status of the process. This is an enum (base::TerminationStatus in
-    base/process/kill.h) but the values vary by platform so we cannot use a
-    regular enum metric. This is temporary debugging for
-    https://crbug.com/1234634.
-  </summary>
-</histogram>
-
-<histogram name="Event.PageShow.Persisted.{Event}.Time" units="ms"
-    expires_after="2022-10-01">
-  <owner>hajimehoshi@chromium.org</owner>
-  <owner>fergal@chromium.org</owner>
-  <summary>
-    When we send a PageLifecycleState update that should trigger a pageshow
-    event with its persisted flag set and have not yet received an ack, we log
-    how long it takes for certain events to occur. This is temporary debugging
-    for https://crbug.com/1234634.
-  </summary>
-  <token key="Event">
-    <variant name="Termination.Normal" summary="renderer exited normally"/>
-    <variant name="Termination.Unexpected"
-        summary="renderer exited unexpectedly"/>
-    <variant name="ViewDestroyed" summary="renderer view host was destroyed"/>
-  </token>
-</histogram>
-
 <histogram name="Event.PassiveListeners" enum="EventResultType"
     expires_after="2024-05-19">
   <owner>dtapuska@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/extensions/histograms.xml b/tools/metrics/histograms/metadata/extensions/histograms.xml
index 8baa587..79c4b693 100644
--- a/tools/metrics/histograms/metadata/extensions/histograms.xml
+++ b/tools/metrics/histograms/metadata/extensions/histograms.xml
@@ -1556,16 +1556,6 @@
   </summary>
 </histogram>
 
-<histogram name="Extensions.FaviconResourceRequested" enum="ExtensionType"
-    expires_after="2021-01-31">
-  <owner>archanasimha@chromium.org</owner>
-  <owner>extensions-core@chromium.org</owner>
-  <summary>
-    Records when an extension with the chrome://favicon host permission makes a
-    network level request for a favicon resource.
-  </summary>
-</histogram>
-
 <histogram name="Extensions.FileAccessAllowed" units="units"
     expires_after="2023-07-07">
   <owner>rdevlin.cronin@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/gpu/histograms.xml b/tools/metrics/histograms/metadata/gpu/histograms.xml
index adda813..a998fc3 100644
--- a/tools/metrics/histograms/metadata/gpu/histograms.xml
+++ b/tools/metrics/histograms/metadata/gpu/histograms.xml
@@ -832,15 +832,6 @@
   </summary>
 </histogram>
 
-<histogram name="GPU.GPUProcessInitialized" enum="BooleanSuccess"
-    expires_after="2021-01-03">
-  <owner>vmiura@chromium.org</owner>
-  <summary>
-    Whether the GPU process successfully initialized or failed and then exitted
-    normally.
-  </summary>
-</histogram>
-
 <histogram name="GPU.GPUProcessLaunchTime" units="ms"
     expires_after="2024-05-19">
   <owner>vmiura@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/ios/histograms.xml b/tools/metrics/histograms/metadata/ios/histograms.xml
index cb046cac8..be88302 100644
--- a/tools/metrics/histograms/metadata/ios/histograms.xml
+++ b/tools/metrics/histograms/metadata/ios/histograms.xml
@@ -1998,7 +1998,7 @@
 
 <histogram
     name="IOS.OverflowMenu.Customization.DestinationsReordered.FirstPosition"
-    enum="IOSOverflowMenuDestination" expires_after="2024-04-28">
+    enum="IOSOverflowMenuDestination" expires_after="2024-06-30">
   <owner>rkgibson@google.com</owner>
   <owner>bling-mony-pod@google.com</owner>
   <summary>
@@ -2096,6 +2096,17 @@
   </summary>
 </histogram>
 
+<histogram name="IOS.OverflowMenu.UserScrolledToEndAndStartedCustomization"
+    enum="Boolean" expires_after="2024-04-28">
+  <owner>rkgibson@google.com</owner>
+  <owner>bling-team@google.com</owner>
+  <summary>
+    Fired whenever the user ends an overflow menu session after having scrolled
+    to the end of the menu. Records whether the user started the menu
+    customization flow during that session.
+  </summary>
+</histogram>
+
 <histogram name="IOS.PageLoad.DefaultModeMobile" enum="Boolean"
     expires_after="2024-01-28">
   <owner>gambard@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/navigation/histograms.xml b/tools/metrics/histograms/metadata/navigation/histograms.xml
index db1d9eb..28ef4e2 100644
--- a/tools/metrics/histograms/metadata/navigation/histograms.xml
+++ b/tools/metrics/histograms/metadata/navigation/histograms.xml
@@ -923,16 +923,6 @@
   </summary>
 </histogram>
 
-<histogram name="Navigation.MainFrameFormSubmission.SiteEngagementLevel"
-    enum="SiteEngagementLevel" expires_after="2021-04-04">
-  <owner>meacer@chromium.org</owner>
-  <owner>security-enamel@chromium.org</owner>
-  <summary>
-    Site engagement level of the URL of the top frame of a form submission. This
-    is a subset of Navigation.MainFrame.SiteEngagementLevel.
-  </summary>
-</histogram>
-
 <histogram name="Navigation.MainFrameHasRTLDomain2" enum="Boolean"
     expires_after="2024-05-19">
   <owner>cthomp@chromium.org</owner>
@@ -1510,19 +1500,6 @@
   </summary>
 </histogram>
 
-<histogram name="Navigation.VerifyDidCommitParams"
-    enum="VerifyDidCommitParamsDifference" expires_after="2021-12-26">
-  <owner>rakina@chromium.org</owner>
-  <owner>altimin@chromium.org</owner>
-  <summary>
-    Logs inconsistencies between browser- vs renderer-calculated values of
-    DidCommitProvisionalLoadParams which are detected in RenderFrameHostImpl's
-    VerifyThatBrowserAndRendererCalculatedDidCommitParamsMatch(). This is used
-    to trigger traces to be uploaded to analyze what happened in these
-    navigations.
-  </summary>
-</histogram>
-
 <histogram name="Navigation.{Stage}.{FrameType}" units="ms"
     expires_after="2023-05-06">
   <owner>cduvall@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/net/enums.xml b/tools/metrics/histograms/metadata/net/enums.xml
index f58bf02..f788f47 100644
--- a/tools/metrics/histograms/metadata/net/enums.xml
+++ b/tools/metrics/histograms/metadata/net/enums.xml
@@ -387,21 +387,6 @@
   <int value="3" label="Enabled over secure connection"/>
 </enum>
 
-<enum name="HttpAuthPromptType">
-  <int value="0" label="Main frame with interstitial">
-    Auth prompt displayed over a blank interstitial
-  </int>
-  <int value="1" label="Main frame without interstitial">
-    Auth prompt displayed for the main frame, without a blank interstitial
-  </int>
-  <int value="2" label="Same origin subresource">
-    Auth prompt displayed for a subresource from the same origin
-  </int>
-  <int value="3" label="Cross origin subresource">
-    Auth prompt displayed for a subresource from a different origin
-  </int>
-</enum>
-
 <enum name="HttpAuthTarget">
   <int value="0" label="Basic Proxy"/>
   <int value="1" label="Basic Secure Proxy"/>
@@ -538,21 +523,6 @@
   <int value="3" label="Chain contained only one certificate"/>
 </enum>
 
-<enum name="NetErrorOfflineSuggestionType">
-  <int value="0" label="Prefetched Page">
-    A Prefetched article that has been offlined.
-  </int>
-  <int value="1" label="Video">
-    A video file previously downloaded by the user.
-  </int>
-  <int value="2" label="Audio">
-    An audio file previously downloaded by the user.
-  </int>
-  <int value="3" label="Other Page">
-    An offline page previously downloaded by the user.
-  </int>
-</enum>
-
 <enum name="NetErrorPageEvents">
   <int value="0" label="Error Page Shown">
     An error page was shown. This bucket encompasses all others and works as a
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml
index 96cee27..aba80ba 100644
--- a/tools/metrics/histograms/metadata/net/histograms.xml
+++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -1723,17 +1723,6 @@
   </summary>
 </histogram>
 
-<histogram name="Net.ErrorPageCounts.SuggestionPresented"
-    enum="NetErrorOfflineSuggestionType" expires_after="2021-12-05">
-  <owner>sclittle@chromium.org</owner>
-  <owner>offline-dev@chromium.org</owner>
-  <summary>
-    Counts of the type of offline content suggestions shown on the network error
-    page. Multiple suggestions can be shown at the same time. Reported when the
-    suggestions are presented.
-  </summary>
-</histogram>
-
 <histogram name="Net.ErrorPageCounts.WebAppAlternativeErrorPage"
     enum="NetErrorCodes" expires_after="2024-04-28">
   <owner>finnur@chromium.org</owner>
@@ -1789,13 +1778,6 @@
   </summary>
 </histogram>
 
-<histogram name="Net.HttpAuthPromptType" enum="HttpAuthPromptType"
-    expires_after="2021-12-26">
-  <owner>meacer@chromium.org</owner>
-  <owner>src/chrome/browser/ui/login/OWNERS</owner>
-  <summary>Type of the HTTP auth prompt displayed.</summary>
-</histogram>
-
 <histogram name="Net.HttpAuthTarget" enum="HttpAuthTarget"
     expires_after="2024-02-29">
   <owner>mpdenton@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/optimization/enums.xml b/tools/metrics/histograms/metadata/optimization/enums.xml
index 597abbb..3838dd2 100644
--- a/tools/metrics/histograms/metadata/optimization/enums.xml
+++ b/tools/metrics/histograms/metadata/optimization/enums.xml
@@ -239,6 +239,17 @@
   <int value="10" label="The request was cancelled"/>
 </enum>
 
+<enum name="OptimizationGuideModelQualityLogsUploadStatus">
+  <int value="0" label="Unknown"/>
+  <int value="1" label="UploadSuccessful">Logs upload was successful.</int>
+  <int value="2" label="Logging Not Enabled">
+    Upload is disabled due to logging feature not enabled.
+  </int>
+  <int value="3" label="Net Error">
+    Upload was not successful because of network error.
+  </int>
+</enum>
+
 <enum name="OptimizationGuideOnDeviceAddContextResult">
   <int value="0" label="Used Server"/>
   <int value="1" label="Used on-device">
@@ -301,6 +312,9 @@
   <int value="7" label="Too many recent timeouts">
     The service took too long to respond too many times in a row.
   </int>
+  <int value="8" label="Safety model not available">
+    The on-device safety model is required but not available.
+  </int>
 </enum>
 
 <enum name="OptimizationGuideOptimizationFilterStatus">
diff --git a/tools/metrics/histograms/metadata/optimization/histograms.xml b/tools/metrics/histograms/metadata/optimization/histograms.xml
index b5b402b..288c781 100644
--- a/tools/metrics/histograms/metadata/optimization/histograms.xml
+++ b/tools/metrics/histograms/metadata/optimization/histograms.xml
@@ -31,6 +31,7 @@
 <variants name="ModelExecutionFeature">
   <variant name="Compose" summary="Compose"/>
   <variant name="TabOrganization" summary="Tab Organization"/>
+  <variant name="Test" summary="Test"/>
   <variant name="Unknown" summary="Unknown"/>
   <variant name="WallpaperSearch" summary="Wallpaper search"/>
 </variants>
@@ -963,6 +964,20 @@
   </summary>
 </histogram>
 
+<histogram
+    name="OptimizationGuide.ModelQualityLogsUploaderService.UploadStatus.{ModelExecutionFeature}"
+    enum="OptimizationGuideModelQualityLogsUploadStatus"
+    expires_after="2024-05-10">
+  <owner>sophiechang@chromium.org</owner>
+  <owner>sreejakshetty@chromium.org</owner>
+  <summary>
+    The status of model quality logs upload request for each
+    {ModelExecutionFeature}. Uploaded once for each model quality logs upload
+    request.
+  </summary>
+  <token key="ModelExecutionFeature" variants="ModelExecutionFeature"/>
+</histogram>
+
 <histogram name="OptimizationGuide.OptimizationFilterStatus.{OptimizationType}"
     enum="OptimizationGuideOptimizationFilterStatus" expires_after="2024-05-12">
   <owner>mcrouse@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml
index 44682045..b735ead 100644
--- a/tools/metrics/histograms/metadata/others/histograms.xml
+++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -7117,33 +7117,6 @@
   </summary>
 </histogram>
 
-<histogram name="NQE.Prefs.ReadCount" units="count" expires_after="2021-10-10">
-  <owner>tbansal@chromium.org</owner>
-  <owner>bengr@chromium.org</owner>
-  <summary>
-    Number of times the network quality prefs were read by the network quality
-    estimator.
-  </summary>
-</histogram>
-
-<histogram name="NQE.Prefs.ReadSize" units="count" expires_after="2021-10-10">
-  <owner>tbansal@chromium.org</owner>
-  <owner>bengr@chromium.org</owner>
-  <summary>
-    Count of the number of network IDs in the prefs read by the network quality
-    estimator.
-  </summary>
-</histogram>
-
-<histogram name="NQE.Prefs.WriteCount" units="count" expires_after="2021-10-10">
-  <owner>tbansal@chromium.org</owner>
-  <owner>bengr@chromium.org</owner>
-  <summary>
-    Number of times the network quality prefs were written by the network
-    quality estimator.
-  </summary>
-</histogram>
-
 <histogram name="NQE.RTT.ObservationSource" enum="NQEObservationSource"
     expires_after="2022-02-20">
   <owner>tbansal@chromium.org</owner>
@@ -7451,18 +7424,6 @@
   </summary>
 </histogram>
 
-<histogram name="OriginTrials.ValidationResult" enum="OriginTrialTokenStatus"
-    expires_after="2021-10-10">
-  <owner>chasej@chromium.org</owner>
-  <owner>iclelland@chromium.org</owner>
-  <owner>feature-control@chromium.org</owner>
-  <summary>
-    Counts the results of token validation checks to enable experimental
-    features. The result for each token validation check is counted once per
-    token per execution context (e.g. page, worker).
-  </summary>
-</histogram>
-
 <histogram name="OSCrypt.AppBoundEncryption.Decrypt.ResultCode" enum="Hresult"
     expires_after="2024-06-02">
   <owner>wfh@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/page/histograms.xml b/tools/metrics/histograms/metadata/page/histograms.xml
index 79dddc9f..5a8824b 100644
--- a/tools/metrics/histograms/metadata/page/histograms.xml
+++ b/tools/metrics/histograms/metadata/page/histograms.xml
@@ -1985,7 +1985,7 @@
 </histogram>
 
 <histogram name="PageLoad.Experimental.PageVisitFinalStatus"
-    enum="PageVisitFinalStatus" expires_after="2023-12-22">
+    enum="PageVisitFinalStatus" expires_after="2024-12-22">
   <owner>iclelland@chromium.org</owner>
   <owner>speed-metrics-dev@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/permissions/histograms.xml b/tools/metrics/histograms/metadata/permissions/histograms.xml
index 1ee5df50..d311dfd 100644
--- a/tools/metrics/histograms/metadata/permissions/histograms.xml
+++ b/tools/metrics/histograms/metadata/permissions/histograms.xml
@@ -352,18 +352,6 @@
   </summary>
 </histogram>
 
-<histogram name="Permissions.CrowdDeny.PreloadData.WarningOnly" enum="Boolean"
-    expires_after="2021-10-25">
-  <owner>andypaicu@chromium.org</owner>
-  <owner>engedy@chromium.org</owner>
-  <owner>hkamila@chromium.org</owner>
-  <summary>
-    Records, each time a notification permission prompt is about to be shown,
-    the whether there is preload data that indicates the origin being on a
-    warning list.
-  </summary>
-</histogram>
-
 <histogram name="Permissions.CrowdDeny.SafeBrowsing.RequestDuration" units="ms"
     expires_after="2024-11-30">
   <owner>andypaicu@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/security/histograms.xml b/tools/metrics/histograms/metadata/security/histograms.xml
index e3aaa956..0888cb8c 100644
--- a/tools/metrics/histograms/metadata/security/histograms.xml
+++ b/tools/metrics/histograms/metadata/security/histograms.xml
@@ -292,7 +292,7 @@
 </histogram>
 
 <histogram name="Security.JSONParser.ParsingTime" units="microseconds"
-    expires_after="M120">
+    expires_after="M124">
   <owner>djmitche@chromium.org</owner>
   <owner>chrome-platform-security@google.com</owner>
   <summary>
@@ -306,6 +306,8 @@
     mostly interested in comparing C++ vs Rust and it seems okay to assume that
     such comparison would give similar results for the filtered and non-filtered
     population.
+
+    Data for this metric is missing before M122.
   </summary>
 </histogram>
 
diff --git a/tools/metrics/histograms/metadata/tab/histograms.xml b/tools/metrics/histograms/metadata/tab/histograms.xml
index 0563c1f..e24a34b 100644
--- a/tools/metrics/histograms/metadata/tab/histograms.xml
+++ b/tools/metrics/histograms/metadata/tab/histograms.xml
@@ -204,8 +204,21 @@
   </token>
 </histogram>
 
+<histogram name="Tab.HasCustomUnderPageBackgroundColor" units="BooleanPresent"
+    expires_after="2024-11-29">
+  <owner>gambard@chromium.org</owner>
+  <owner>bling-team@google.com</owner>
+  <summary>
+    [iOS] Whether a page has a custom under page background color, recorded when
+    the page is fully loaded. The default value of this color is from the
+    background colors of the &quot;html&quot; and &quot;body&quot; elements and
+    the background color of the web view. By default it is white, so this
+    histogram only records it as custom if it is not white with no alpha.
+  </summary>
+</histogram>
+
 <histogram name="Tab.HasThemeColor" units="BooleanPresent"
-    expires_after="2024-09-29">
+    expires_after="2024-11-29">
   <owner>gambard@chromium.org</owner>
   <owner>bling-team@google.com</owner>
   <summary>
diff --git a/tools/visual_debugger/app.html b/tools/visual_debugger/app.html
index 1ab2b78..9dba9e48 100644
--- a/tools/visual_debugger/app.html
+++ b/tools/visual_debugger/app.html
@@ -157,9 +157,10 @@
 </div>
 
 <div id='logsPanel'>
-  <div class='panelSection'>
+  <div class='panelSection collapsible'>
     <div class='sectionTitle'>
       Logs
+      [<span class="plus">+</span><span class="minus">-</span>]
       <!--input size=40 placeholder='Comma separated filter ...'>(TODO)</input-->
     </div>
     <div class='section'>
@@ -168,10 +169,11 @@
   </div>
 </div>
 
-<div class='panelSection'>
+<div class='panelSection collapsible'>
   <div class='sectionTitle'
     title="Filter debug data stream. Filter operations occur in a left to right order with first match being applied.">
     <i class="material-icons-outlined">filter_list</i> Filters
+    [<span class="plus">+</span><span class="minus">-</span>]
   </div>
   <div class='section'>
     <div id='filters' class="mdc-chip-set mdc-chip-set--filter" role="grid"
@@ -184,19 +186,23 @@
   </div>
 </div>
 
-<div class='panelSection'>
+<div class='panelSection collapsible'>
   <div class='sectionTitle'>
     <i class="material-symbols-outlined">
       airwave
     </i>
     Threads
+    [<span class="plus">+</span><span class="minus">-</span>]
   </div>
 
   <div id='threads' class='section'></div>
 </div>
 
-<div class='panelSection'>
-  <div class='sectionTitle'>Viewer Controls</div>
+<div class='panelSection collapsible'>
+  <div class='sectionTitle'>
+    Viewer Controls
+    [<span class="plus">+</span><span class="minus">-</span>]
+  </div>
   <div class='section' id='controls'>
     <div id='buttons'>
       <button class="mdc-button mdc-button--outline" id='prev'>
@@ -219,11 +225,11 @@
       </button>
 
     </div>
-    <div class='panelSection'>
+    <div>
       <div class='sectionTitle'>Frame Selection</div>
       <input type='range' min='0' max='0' value='0' id='scrubberframe'></input>
     </div>
-    <div class='panelSection'>
+    <div>
       <div class='sectionTitle'>Draw Selection<span id="drawRange"></span></div>
       <div class="minMaxScrubber">
         <input type="range" id='minDrawScrubber' class="scrubber"
@@ -235,9 +241,10 @@
   </div>
 </div>
 
-<div>
+<div class="panelSection collapsible">
   <div class='sectionTitle'>
     Viewer
+    [<span class="plus">+</span><span class="minus">-</span>]
   </div>
   <div style='float: right' class='sectionTitle'>
     Scale
@@ -407,6 +414,14 @@
       f.click();
     });
 
+    document.querySelectorAll('.panelSection.collapsible').forEach(
+        (section) => {
+          let title = section.querySelector('.sectionTitle');
+          title.addEventListener('click', () => {
+            section.classList.toggle('collapsed');
+          });
+        });
+
     setUpPlayer();
     restoreFilters();
   }
diff --git a/tools/visual_debugger/style.css b/tools/visual_debugger/style.css
index 2daa61b3..f656f5b 100644
--- a/tools/visual_debugger/style.css
+++ b/tools/visual_debugger/style.css
@@ -105,6 +105,29 @@
   padding-bottom: 10px;
 }
 
+.collapsible.collapsed {
+  margin-bottom: 10px;
+}
+
+.collapsible.collapsed .section {
+  display: none;
+}
+
+.collapsible.collapsed .minus {
+  display: none;
+}
+
+.collapsible:not(.collapsed) .plus {
+  display: none;
+}
+
+.minus,
+.plus {
+  display: inline-block;
+  min-width: 30px;
+  text-align: center;
+}
+
 #filter-container {
   max-width: 450px;
   min-width: 350px;
diff --git a/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogManager.java b/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogManager.java
index 4eac72c..f4e3df8 100644
--- a/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogManager.java
+++ b/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogManager.java
@@ -258,6 +258,13 @@
     }
 
     /**
+     * @return Whether dialogs of the specified type are suspended.
+     */
+    public boolean isSuspended(@ModalDialogType int dialogType) {
+        return mSuspendedTypes.contains(dialogType);
+    }
+
+    /**
      * @return The type of dialog showing, or last type that was shown.
      */
     public @ModalDialogType int getCurrentType() {
diff --git a/ui/android/junit/src/org/chromium/ui/modaldialog/ModalDialogManagerTest.java b/ui/android/junit/src/org/chromium/ui/modaldialog/ModalDialogManagerTest.java
index 4fec0075..ed3847f 100644
--- a/ui/android/junit/src/org/chromium/ui/modaldialog/ModalDialogManagerTest.java
+++ b/ui/android/junit/src/org/chromium/ui/modaldialog/ModalDialogManagerTest.java
@@ -375,6 +375,8 @@
         assertOnDismissCalled(mDialogModels.get(0), 0);
         assertOnDismissCalled(mDialogModels.get(1), 0);
         assertFalse(mModalDialogManager.isShowing());
+        assertFalse(mModalDialogManager.isSuspended(ModalDialogType.APP));
+        assertTrue(mModalDialogManager.isSuspended(ModalDialogType.TAB));
         assertNull(mModalDialogManager.getPendingDialogsForTest(ModalDialogType.APP));
         assertEquals(2, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.TAB).size());
 
@@ -405,11 +407,13 @@
 
         // Suspend all tab modal dialogs.
         int token = mModalDialogManager.suspendType(ModalDialogType.TAB);
+        assertTrue(mModalDialogManager.isSuspended(ModalDialogType.TAB));
         assertFalse(mModalDialogManager.isShowing());
         assertEquals(3, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.TAB).size());
 
         // Resume tab modal dialogs.
         mModalDialogManager.resumeType(ModalDialogType.TAB, token);
+        assertFalse(mModalDialogManager.isSuspended(ModalDialogType.TAB));
         assertEquals(mDialogModels.get(0), mModalDialogManager.getCurrentDialogForTest());
         assertEquals(2, mModalDialogManager.getPendingDialogsForTest(ModalDialogType.TAB).size());
     }
@@ -424,7 +428,7 @@
                 ModalDialogManager.ModalDialogPriority.VERY_HIGH,
                 false);
         // Suspend the APP type and check we are still showing the very_high priority dialog.
-        int token = mModalDialogManager.suspendType(ModalDialogType.APP);
+        mModalDialogManager.suspendType(ModalDialogType.APP);
         assertTrue(mModalDialogManager.isShowing());
     }
 
@@ -438,7 +442,7 @@
                 ModalDialogManager.ModalDialogPriority.VERY_HIGH,
                 false);
         // Suspend the APP type and check we are still showing the very_high priority dialog.
-        int token = mModalDialogManager.suspendType(ModalDialogType.TAB);
+        mModalDialogManager.suspendType(ModalDialogType.TAB);
         assertTrue(mModalDialogManager.isShowing());
     }
 
@@ -453,7 +457,7 @@
                 false);
 
         // Suspend the APP type.
-        int token = mModalDialogManager.suspendType(ModalDialogType.APP);
+        mModalDialogManager.suspendType(ModalDialogType.APP);
         assertFalse(mModalDialogManager.isShowing());
 
         // Create a new dialog of the same type(!) but with a very_high priority and check it's
diff --git a/ui/base/models/dialog_model_field.cc b/ui/base/models/dialog_model_field.cc
index e7a3de3..6555304 100644
--- a/ui/base/models/dialog_model_field.cc
+++ b/ui/base/models/dialog_model_field.cc
@@ -5,6 +5,7 @@
 #include "ui/base/models/dialog_model_field.h"
 
 #include <string>
+#include <utility>
 
 #include "base/functional/bind.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -43,8 +44,7 @@
 DialogModelLabel::DialogModelLabel(std::u16string fixed_string)
     : message_id_(-1), string_(std::move(fixed_string)) {}
 
-const std::u16string& DialogModelLabel::GetString(
-    base::PassKey<DialogModelHost>) const {
+const std::u16string& DialogModelLabel::GetString() const {
   CHECK(replacements_.empty(), base::NotFatalUntil::M123);
   return string_;
 }
@@ -105,45 +105,6 @@
 
 DialogModelField::~DialogModelField() = default;
 
-DialogModelButton* DialogModelField::AsButton(base::PassKey<DialogModelHost>) {
-  return AsButton();
-}
-
-DialogModelParagraph* DialogModelField::AsParagraph(
-    base::PassKey<DialogModelHost>) {
-  return AsParagraph();
-}
-
-DialogModelCheckbox* DialogModelField::AsCheckbox(
-    base::PassKey<DialogModelHost>) {
-  return AsCheckbox();
-}
-
-DialogModelCombobox* DialogModelField::AsCombobox(
-    base::PassKey<DialogModelHost>) {
-  return AsCombobox();
-}
-
-DialogModelTextfield* DialogModelField::AsTextfield(
-    base::PassKey<DialogModelHost>) {
-  return AsTextfield();
-}
-
-const DialogModelMenuItem* DialogModelField::AsMenuItem(
-    base::PassKey<DialogModelHost>) const {
-  return AsMenuItem();
-}
-
-DialogModelMenuItem* DialogModelField::AsMenuItem(
-    base::PassKey<DialogModelHost>) {
-  return const_cast<DialogModelMenuItem*>(AsMenuItem());
-}
-
-DialogModelCustomField* DialogModelField::AsCustomField(
-    base::PassKey<DialogModelHost>) {
-  return AsCustomField();
-}
-
 DialogModelButton* DialogModelField::AsButton() {
   CHECK_EQ(type_, kButton, base::NotFatalUntil::M123);
   return static_cast<DialogModelButton*>(this);
@@ -164,6 +125,10 @@
   return static_cast<DialogModelCombobox*>(this);
 }
 
+DialogModelMenuItem* DialogModelField::AsMenuItem() {
+  return const_cast<DialogModelMenuItem*>(std::as_const(*this).AsMenuItem());
+}
+
 const DialogModelMenuItem* DialogModelField::AsMenuItem() const {
   CHECK_EQ(type_, kMenuItem, base::NotFatalUntil::M123);
   return static_cast<const DialogModelMenuItem*>(this);
@@ -230,7 +195,7 @@
 
 DialogModelButton::~DialogModelButton() = default;
 
-void DialogModelButton::OnPressed(base::PassKey<DialogModelHost>,
+void DialogModelButton::OnPressed(base::PassKey<DialogModelFieldHost>,
                                   const Event& event) {
   callback_.Run(event);
 }
@@ -254,7 +219,7 @@
 
 DialogModelCheckbox::~DialogModelCheckbox() = default;
 
-void DialogModelCheckbox::OnChecked(base::PassKey<DialogModelHost>,
+void DialogModelCheckbox::OnChecked(base::PassKey<DialogModelFieldHost>,
                                     bool is_checked) {
   is_checked_ = is_checked;
 }
@@ -288,12 +253,13 @@
 
 DialogModelCombobox::~DialogModelCombobox() = default;
 
-void DialogModelCombobox::OnSelectedIndexChanged(base::PassKey<DialogModelHost>,
-                                                 size_t selected_index) {
+void DialogModelCombobox::OnSelectedIndexChanged(
+    base::PassKey<DialogModelFieldHost>,
+    size_t selected_index) {
   selected_index_ = selected_index;
 }
 
-void DialogModelCombobox::OnPerformAction(base::PassKey<DialogModelHost>) {
+void DialogModelCombobox::OnPerformAction(base::PassKey<DialogModelFieldHost>) {
   if (callback_)
     callback_.Run();
 }
@@ -328,7 +294,7 @@
 
 DialogModelMenuItem::~DialogModelMenuItem() = default;
 
-void DialogModelMenuItem::OnActivated(base::PassKey<DialogModelHost> pass_key,
+void DialogModelMenuItem::OnActivated(base::PassKey<DialogModelFieldHost>,
                                       int event_flags) {
   CHECK(callback_, base::NotFatalUntil::M123);
   callback_.Run(event_flags);
@@ -368,7 +334,7 @@
 
 DialogModelTextfield::~DialogModelTextfield() = default;
 
-void DialogModelTextfield::OnTextChanged(base::PassKey<DialogModelHost>,
+void DialogModelTextfield::OnTextChanged(base::PassKey<DialogModelFieldHost>,
                                          std::u16string text) {
   text_ = std::move(text);
 }
diff --git a/ui/base/models/dialog_model_field.h b/ui/base/models/dialog_model_field.h
index 4ec19efa..aaac578 100644
--- a/ui/base/models/dialog_model_field.h
+++ b/ui/base/models/dialog_model_field.h
@@ -28,12 +28,20 @@
 class DialogModelCheckbox;
 class DialogModelCombobox;
 class DialogModelCustomField;
-class DialogModelHost;
 class DialogModelMenuItem;
 class DialogModelSection;
 class DialogModelTextfield;
 class Event;
 
+class DialogModelFieldHost {
+ protected:
+  // This PassKey is used to make sure that some methods on DialogModel
+  // are only called as part of the host integration.
+  static base::PassKey<DialogModelFieldHost> GetPassKey() {
+    return base::PassKey<DialogModelFieldHost>();
+  }
+};
+
 // TODO(pbos): Move this to separate header.
 // DialogModelLabel is an exception to below classes. This is not a
 // DialogModelField but rather represents a text label and styling. This is used
@@ -103,7 +111,7 @@
   // is required to style the final label appropriately and support replacement
   // callbacks. The caller is responsible for checking replacements().empty()
   // before calling this.
-  const std::u16string& GetString(base::PassKey<DialogModelHost>) const;
+  const std::u16string& GetString() const;
 
   DialogModelLabel& set_is_secondary() {
     is_secondary_ = true;
@@ -115,18 +123,13 @@
     return *this;
   }
 
-  int message_id(base::PassKey<DialogModelHost>) const { return message_id_; }
-  const std::vector<TextReplacement>& replacements(
-      base::PassKey<DialogModelHost>) const {
+  int message_id() const { return message_id_; }
+  const std::vector<TextReplacement>& replacements() const {
     return replacements_;
   }
 
-  bool is_secondary(base::PassKey<DialogModelHost>) const {
-    return is_secondary_;
-  }
-  bool allow_character_break(base::PassKey<DialogModelHost>) const {
-    return allow_character_break_;
-  }
+  bool is_secondary() const { return is_secondary_; }
+  bool allow_character_break() const { return allow_character_break_; }
 
  private:
   explicit DialogModelLabel(int message_id,
@@ -192,22 +195,19 @@
   Type type() const { return type_; }
   bool is_visible() { return is_visible_; }
 
-  // Methods with base::PassKey<DialogModelHost> are only intended to be called
-  // by the DialogModelHost implementation.
-  const base::flat_set<Accelerator>& accelerators(
-      base::PassKey<DialogModelHost>) const {
+  const base::flat_set<Accelerator>& accelerators() const {
     return accelerators_;
   }
-  ElementIdentifier id(base::PassKey<DialogModelHost>) const { return id_; }
-  DialogModelButton* AsButton(base::PassKey<DialogModelHost>);
-  DialogModelParagraph* AsParagraph(base::PassKey<DialogModelHost>);
-  DialogModelCheckbox* AsCheckbox(base::PassKey<DialogModelHost>);
-  DialogModelCombobox* AsCombobox(base::PassKey<DialogModelHost>);
-  DialogModelMenuItem* AsMenuItem(base::PassKey<DialogModelHost>);
-  const DialogModelMenuItem* AsMenuItem(base::PassKey<DialogModelHost>) const;
-  DialogModelTextfield* AsTextfield(base::PassKey<DialogModelHost>);
-  DialogModelSection* AsSection(base::PassKey<DialogModelHost>);
-  DialogModelCustomField* AsCustomField(base::PassKey<DialogModelHost>);
+  ElementIdentifier id() const { return id_; }
+  DialogModelButton* AsButton();
+  DialogModelParagraph* AsParagraph();
+  DialogModelCheckbox* AsCheckbox();
+  DialogModelCombobox* AsCombobox();
+  DialogModelMenuItem* AsMenuItem();
+  const DialogModelMenuItem* AsMenuItem() const;
+  DialogModelTextfield* AsTextfield();
+  DialogModelSection* AsSection();
+  DialogModelCustomField* AsCustomField();
 
  protected:
   DialogModelField(Type type,
@@ -215,14 +215,6 @@
                    base::flat_set<Accelerator> accelerators,
                    const DialogModelField::Params& params);
 
-  DialogModelButton* AsButton();
-  DialogModelParagraph* AsParagraph();
-  DialogModelCheckbox* AsCheckbox();
-  DialogModelCombobox* AsCombobox();
-  const DialogModelMenuItem* AsMenuItem() const;
-  DialogModelTextfield* AsTextfield();
-  DialogModelCustomField* AsCustomField();
-
   void set_visible(bool visible) { is_visible_ = visible; }
 
  private:
@@ -276,17 +268,10 @@
   DialogModelButton& operator=(const DialogModelButton&) = delete;
   ~DialogModelButton() override;
 
-  // Methods with base::PassKey<DialogModelHost> are only intended to be called
-  // by the DialogModelHost implementation.
-  const std::u16string& label(base::PassKey<DialogModelHost>) const {
-    return label_;
-  }
-  const absl::optional<ButtonStyle> style(
-      base::PassKey<DialogModelHost>) const {
-    return style_;
-  }
-  bool is_enabled(base::PassKey<DialogModelHost>) const { return is_enabled_; }
-  void OnPressed(base::PassKey<DialogModelHost>, const Event& event);
+  const std::u16string& label() const { return label_; }
+  const absl::optional<ButtonStyle> style() const { return style_; }
+  bool is_enabled() const { return is_enabled_; }
+  void OnPressed(base::PassKey<DialogModelFieldHost>, const Event& event);
 
  private:
   friend class DialogModel;
@@ -310,13 +295,9 @@
   DialogModelParagraph& operator=(const DialogModelParagraph&) = delete;
   ~DialogModelParagraph() override;
 
-  const DialogModelLabel& label(base::PassKey<DialogModelHost>) const {
-    return label_;
-  }
+  const DialogModelLabel& label() const { return label_; }
 
-  const std::u16string header(base::PassKey<DialogModelHost>) const {
-    return header_;
-  }
+  const std::u16string header() const { return header_; }
 
  private:
   const DialogModelLabel label_;
@@ -358,10 +339,8 @@
 
   bool is_checked() const { return is_checked_; }
 
-  void OnChecked(base::PassKey<DialogModelHost>, bool is_checked);
-  const DialogModelLabel& label(base::PassKey<DialogModelHost>) const {
-    return label_;
-  }
+  void OnChecked(base::PassKey<DialogModelFieldHost>, bool is_checked);
+  const DialogModelLabel& label() const { return label_; }
 
  private:
   const DialogModelLabel label_;
@@ -421,17 +400,11 @@
   size_t selected_index() const { return selected_index_; }
   ui::ComboboxModel* combobox_model() { return combobox_model_.get(); }
 
-  // Methods with base::PassKey<DialogModelHost> are only intended to be called
-  // by the DialogModelHost implementation.
-  const std::u16string& label(base::PassKey<DialogModelHost>) const {
-    return label_;
-  }
-  const std::u16string& accessible_name(base::PassKey<DialogModelHost>) const {
-    return accessible_name_;
-  }
-  void OnSelectedIndexChanged(base::PassKey<DialogModelHost>,
+  const std::u16string& label() const { return label_; }
+  const std::u16string& accessible_name() const { return accessible_name_; }
+  void OnSelectedIndexChanged(base::PassKey<DialogModelFieldHost>,
                               size_t selected_index);
-  void OnPerformAction(base::PassKey<DialogModelHost>);
+  void OnPerformAction(base::PassKey<DialogModelFieldHost>);
 
  private:
   friend class DialogModel;
@@ -479,14 +452,10 @@
   DialogModelMenuItem& operator=(const DialogModelMenuItem&) = delete;
   ~DialogModelMenuItem() override;
 
-  // Methods with base::PassKey<DialogModelHost> are only intended to be called
-  // by the DialogModelHost implementation.
-  const ImageModel& icon(base::PassKey<DialogModelHost>) const { return icon_; }
-  const std::u16string& label(base::PassKey<DialogModelHost>) const {
-    return label_;
-  }
-  bool is_enabled(base::PassKey<DialogModelHost>) const { return is_enabled_; }
-  void OnActivated(base::PassKey<DialogModelHost>, int event_flags);
+  const ImageModel& icon() const { return icon_; }
+  const std::u16string& label() const { return label_; }
+  bool is_enabled() const { return is_enabled_; }
+  void OnActivated(base::PassKey<DialogModelFieldHost>, int event_flags);
 
  private:
   const ImageModel icon_;
@@ -548,15 +517,9 @@
 
   const std::u16string& text() const { return text_; }
 
-  // Methods with base::PassKey<DialogModelHost> are only intended to be called
-  // by the DialogModelHost implementation.
-  const std::u16string& label(base::PassKey<DialogModelHost>) const {
-    return label_;
-  }
-  const std::u16string& accessible_name(base::PassKey<DialogModelHost>) const {
-    return accessible_name_;
-  }
-  void OnTextChanged(base::PassKey<DialogModelHost>, std::u16string text);
+  const std::u16string& label() const { return label_; }
+  const std::u16string& accessible_name() const { return accessible_name_; }
+  void OnTextChanged(base::PassKey<DialogModelFieldHost>, std::u16string text);
 
  private:
   friend class DialogModel;
@@ -584,11 +547,7 @@
   DialogModelCustomField& operator=(const DialogModelCustomField&) = delete;
   ~DialogModelCustomField() override;
 
-  // Methods with base::PassKey<DialogModelHost> are only intended to be called
-  // by the DialogModelHost implementation.
-  DialogModelCustomField::Field* field(base::PassKey<DialogModelHost>) {
-    return field_.get();
-  }
+  DialogModelCustomField::Field* field() { return field_.get(); }
 
  private:
   friend class DialogModel;
diff --git a/ui/base/models/dialog_model_menu_model_adapter.cc b/ui/base/models/dialog_model_menu_model_adapter.cc
index ed47847..7e9d78f 100644
--- a/ui/base/models/dialog_model_menu_model_adapter.cc
+++ b/ui/base/models/dialog_model_menu_model_adapter.cc
@@ -25,7 +25,7 @@
 }
 
 size_t DialogModelMenuModelAdapter::GetItemCount() const {
-  return model_->fields(GetPassKey()).size();
+  return model_->fields(DialogModelHost::GetPassKey()).size();
 }
 
 MenuModel::ItemType DialogModelMenuModelAdapter::GetTypeAt(size_t index) const {
@@ -48,7 +48,7 @@
 }
 
 std::u16string DialogModelMenuModelAdapter::GetLabelAt(size_t index) const {
-  return GetField(index)->AsMenuItem(GetPassKey())->label(GetPassKey());
+  return GetField(index)->AsMenuItem()->label();
 }
 
 bool DialogModelMenuModelAdapter::IsItemDynamicAt(size_t index) const {
@@ -72,7 +72,7 @@
 }
 
 ImageModel DialogModelMenuModelAdapter::GetIconAt(size_t index) const {
-  return GetField(index)->AsMenuItem(GetPassKey())->icon(GetPassKey());
+  return GetField(index)->AsMenuItem()->icon();
 }
 
 ButtonMenuItemModel* DialogModelMenuModelAdapter::GetButtonMenuItemAt(
@@ -85,7 +85,7 @@
 
   const DialogModelField* const field = GetField(index);
   return field->type() != DialogModelField::kSeparator &&
-         field->AsMenuItem(GetPassKey())->is_enabled(GetPassKey());
+         field->AsMenuItem()->is_enabled();
 }
 
 ui::ElementIdentifier DialogModelMenuModelAdapter::GetElementIdentifierAt(
@@ -93,7 +93,7 @@
   CHECK_LT(index, GetItemCount(), base::NotFatalUntil::M123);
 
   const DialogModelField* const field = GetField(index);
-  return field->AsMenuItem(GetPassKey())->id(GetPassKey());
+  return field->AsMenuItem()->id();
 }
 
 MenuModel* DialogModelMenuModelAdapter::GetSubmenuModelAt(size_t index) const {
@@ -107,14 +107,14 @@
 }
 
 void DialogModelMenuModelAdapter::ActivatedAt(size_t index, int event_flags) {
-  DialogModelMenuItem* menu_item = GetField(index)->AsMenuItem(GetPassKey());
-  menu_item->OnActivated(GetPassKey(), event_flags);
+  DialogModelMenuItem* menu_item = GetField(index)->AsMenuItem();
+  menu_item->OnActivated(DialogModelFieldHost::GetPassKey(), event_flags);
 }
 
 const DialogModelField* DialogModelMenuModelAdapter::GetField(
     size_t index) const {
   CHECK_LT(index, GetItemCount(), base::NotFatalUntil::M123);
-  return model_->fields(GetPassKey())[index].get();
+  return model_->fields(DialogModelHost::GetPassKey())[index].get();
 }
 
 DialogModelField* DialogModelMenuModelAdapter::GetField(size_t index) {
diff --git a/ui/base/models/dialog_model_menu_model_adapter.h b/ui/base/models/dialog_model_menu_model_adapter.h
index 123dfe9f..0eb9a64 100644
--- a/ui/base/models/dialog_model_menu_model_adapter.h
+++ b/ui/base/models/dialog_model_menu_model_adapter.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "ui/base/models/dialog_model_field.h"
 #include "ui/base/models/dialog_model_host.h"
 #include "ui/base/models/menu_model.h"
 
@@ -16,6 +17,7 @@
 
 class COMPONENT_EXPORT(UI_BASE) DialogModelMenuModelAdapter final
     : public DialogModelHost,
+      public DialogModelFieldHost,
       public MenuModel {
  public:
   explicit DialogModelMenuModelAdapter(std::unique_ptr<DialogModel> model);
diff --git a/ui/base/resource/data_pack.cc b/ui/base/resource/data_pack.cc
index 8b173a0..ecfb2b4 100644
--- a/ui/base/resource/data_pack.cc
+++ b/ui/base/resource/data_pack.cc
@@ -279,7 +279,16 @@
     }
   }
 
-  // 3) Verify the aliases are within the appropriate bounds.
+  // 3) Verify the entries are ordered correctly.
+  for (size_t i = 0; i < resource_count_; ++i) {
+    if (resource_table_[i].file_offset > resource_table_[i + 1].file_offset) {
+      LOG(ERROR) << "Data pack file corruption: " << "Entry #" << i + 1
+                 << " before Entry #" << i << ".";
+      return false;
+    }
+  }
+
+  // 4) Verify the aliases are within the appropriate bounds.
   for (size_t i = 0; i < alias_count_; ++i) {
     if (alias_table_[i].entry_index >= resource_count_) {
       LOG(ERROR) << "Data pack file corruption: "
@@ -393,6 +402,14 @@
                << "file modified?";
     return absl::nullopt;
   }
+  if (target->file_offset > next_entry->file_offset) {
+    size_t entry_index = target - resource_table_;
+    size_t next_index = next_entry - resource_table_;
+    LOG(ERROR) << "Entry #" << next_index << " in data pack is before Entry #"
+               << entry_index << ". This should have been caught when loading. "
+               << "Was the file modified?";
+    return absl::nullopt;
+  }
 
   MaybePrintResourceId(resource_id);
   return GetStringPieceFromOffset(target->file_offset, next_entry->file_offset,
diff --git a/ui/base/resource/data_pack_literal.cc b/ui/base/resource/data_pack_literal.cc
index caac070..4197ea0 100644
--- a/ui/base/resource/data_pack_literal.cc
+++ b/ui/base/resource/data_pack_literal.cc
@@ -89,6 +89,18 @@
 
 const size_t kSampleCorruptPakSize = sizeof(kSampleCorruptPakContents);
 
+const uint8_t kSampleMisorderedPakContents[] = {
+    0x05, 0x00, 0x00, 0x00,              // version
+    0x01, 0x00, 0x00, 0x00,              // encoding + padding
+    0x02, 0x00, 0x00, 0x00,              // num_resources, num_aliases
+    0x06, 0x00, 0x2a, 0x00, 0x00, 0x00,  // index entry 6 (wrong order)
+    0x04, 0x00, 0x1e, 0x00, 0x00, 0x00,  // index entry 4
+    0x00, 0x00, 0x36, 0x00, 0x00, 0x00,  // extra entry for the size of last
+    't',  'h',  'i',  's',  ' ',  'i',  's', ' ', 'i', 'd', ' ', '4',
+    't',  'h',  'i',  's',  ' ',  'i',  's', ' ', 'i', 'd', ' ', '6'};
+
+const size_t kSampleMisorderedPakSize = sizeof(kSampleMisorderedPakContents);
+
 const uint8_t kSamplePakContents2x[] = {
     0x04, 0x00, 0x00, 0x00,              // header(version
     0x01, 0x00, 0x00, 0x00,              //        no. entries
diff --git a/ui/base/resource/data_pack_literal.h b/ui/base/resource/data_pack_literal.h
index eb5a948..9173ce14 100644
--- a/ui/base/resource/data_pack_literal.h
+++ b/ui/base/resource/data_pack_literal.h
@@ -22,6 +22,8 @@
 extern const size_t kEmptyPakSize;
 extern const uint8_t kSampleCorruptPakContents[];
 extern const size_t kSampleCorruptPakSize;
+extern const uint8_t kSampleMisorderedPakContents[];
+extern const size_t kSampleMisorderedPakSize;
 
 }  // namespace ui
 
diff --git a/ui/base/resource/data_pack_unittest.cc b/ui/base/resource/data_pack_unittest.cc
index 8a0b709..36095bbc 100644
--- a/ui/base/resource/data_pack_unittest.cc
+++ b/ui/base/resource/data_pack_unittest.cc
@@ -341,4 +341,11 @@
 }
 #endif
 
+TEST(DataPackTest, Misordered) {
+  DataPack pack(k100Percent);
+
+  ASSERT_FALSE(pack.LoadFromBuffer(
+      {kSampleMisorderedPakContents, kSampleMisorderedPakSize}));
+}
+
 }  // namespace ui
diff --git a/ui/base/test/test_dialog_model_host.cc b/ui/base/test/test_dialog_model_host.cc
index 5e6594a..8fe1a70 100644
--- a/ui/base/test/test_dialog_model_host.cc
+++ b/ui/base/test/test_dialog_model_host.cc
@@ -34,63 +34,69 @@
 // These are static methods rather than a method on the host because this needs
 // to result with the destruction of the host.
 void TestDialogModelHost::Accept(std::unique_ptr<TestDialogModelHost> host) {
-  host->dialog_model_->OnDialogAcceptAction(GetPassKey());
+  host->dialog_model_->OnDialogAcceptAction(DialogModelHost::GetPassKey());
   DestroyWithoutAction(std::move(host));
 }
 
 void TestDialogModelHost::Cancel(std::unique_ptr<TestDialogModelHost> host) {
-  host->dialog_model_->OnDialogCancelAction(GetPassKey());
+  host->dialog_model_->OnDialogCancelAction(DialogModelHost::GetPassKey());
   DestroyWithoutAction(std::move(host));
 }
 
 void TestDialogModelHost::Close(std::unique_ptr<TestDialogModelHost> host) {
-  host->dialog_model_->OnDialogCloseAction(GetPassKey());
+  host->dialog_model_->OnDialogCloseAction(DialogModelHost::GetPassKey());
   DestroyWithoutAction(std::move(host));
 }
 
 void TestDialogModelHost::DestroyWithoutAction(
     std::unique_ptr<TestDialogModelHost> host) {
-  host->dialog_model_->OnDialogDestroying(GetPassKey());
+  host->dialog_model_->OnDialogDestroying(DialogModelHost::GetPassKey());
   // Note that `host` destroys when going out of scope here.
 }
 
 void TestDialogModelHost::TriggerExtraButton(const ui::Event& event) {
-  dialog_model_->extra_button(GetPassKey())->OnPressed(GetPassKey(), event);
+  dialog_model_->extra_button(DialogModelHost::GetPassKey())
+      ->OnPressed(DialogModelFieldHost::GetPassKey(), event);
 }
 
 DialogModelTextfield* TestDialogModelHost::FindSingleTextfield() {
   // TODO(pbos): Consider validating how "single" this field is.
-  for (const auto& field : dialog_model_->fields(GetPassKey())) {
+  for (const auto& field :
+       dialog_model_->fields(DialogModelHost::GetPassKey())) {
     if (field->type() == ui::DialogModelField::kTextfield) {
-      return field->AsTextfield(GetPassKey());
+      return field->AsTextfield();
     }
   }
   NOTREACHED_NORETURN();
 }
 
 void TestDialogModelHost::SetSingleTextfieldText(std::u16string text) {
-  FindSingleTextfield()->OnTextChanged(GetPassKey(), std::move(text));
+  FindSingleTextfield()->OnTextChanged(DialogModelFieldHost::GetPassKey(),
+                                       std::move(text));
 }
 
 // Bypasses PassKey() requirement for accessing accelerators().
 const base::flat_set<Accelerator>& TestDialogModelHost::GetAccelerators(
     ButtonId button_id) {
-  return GetButton(dialog_model_.get(), button_id, GetPassKey())
-      ->accelerators(GetPassKey());
+  return GetButton(dialog_model_.get(), button_id,
+                   DialogModelHost::GetPassKey())
+      ->accelerators();
 }
 
 const std::u16string& TestDialogModelHost::GetLabel(ButtonId button_id) {
-  return GetButton(dialog_model_.get(), button_id, GetPassKey())
-      ->label(GetPassKey());
+  return GetButton(dialog_model_.get(), button_id,
+                   DialogModelHost::GetPassKey())
+      ->label();
 }
 
 ElementIdentifier TestDialogModelHost::GetId(ButtonId button_id) {
-  return GetButton(dialog_model_.get(), button_id, GetPassKey())
-      ->id(GetPassKey());
+  return GetButton(dialog_model_.get(), button_id,
+                   DialogModelHost::GetPassKey())
+      ->id();
 }
 
 ElementIdentifier TestDialogModelHost::GetInitiallyFocusedField() {
-  return dialog_model_->initially_focused_field(GetPassKey());
+  return dialog_model_->initially_focused_field(DialogModelHost::GetPassKey());
 }
 
 void TestDialogModelHost::Close() {
diff --git a/ui/base/test/test_dialog_model_host.h b/ui/base/test/test_dialog_model_host.h
index d3fb17a1..5564ca30 100644
--- a/ui/base/test/test_dialog_model_host.h
+++ b/ui/base/test/test_dialog_model_host.h
@@ -17,7 +17,8 @@
 
 namespace ui {
 
-class TestDialogModelHost final : public DialogModelHost {
+class TestDialogModelHost final : public DialogModelHost,
+                                  public DialogModelFieldHost {
  public:
   enum class ButtonId {
     kCancel,
diff --git a/ui/views/bubble/bubble_dialog_model_host.cc b/ui/views/bubble/bubble_dialog_model_host.cc
index e6c7d7b..c061b65 100644
--- a/ui/views/bubble/bubble_dialog_model_host.cc
+++ b/ui/views/bubble/bubble_dialog_model_host.cc
@@ -45,8 +45,7 @@
 constexpr int kScrollViewVerticalMargin = 2;
 
 BubbleDialogModelHost::FieldType GetFieldTypeForField(
-    ui::DialogModelField* field,
-    base::PassKey<ui::DialogModelHost> pass_key) {
+    ui::DialogModelField* field) {
   DCHECK(field);
   switch (field->type()) {
     case ui::DialogModelField::kButton:
@@ -68,7 +67,7 @@
       return BubbleDialogModelHost::FieldType::kMenuItem;
     case ui::DialogModelField::kCustom:
       return static_cast<BubbleDialogModelHost::CustomView*>(
-                 field->AsCustomField(pass_key)->field(pass_key))
+                 field->AsCustomField()->field())
           ->field_type();
   }
 }
@@ -93,10 +92,9 @@
 }
 
 int GetDialogTopMargins(LayoutProvider* layout_provider,
-                        ui::DialogModelField* first_field,
-                        base::PassKey<ui::DialogModelHost> pass_key) {
+                        ui::DialogModelField* first_field) {
   const BubbleDialogModelHost::FieldType field_type =
-      first_field ? GetFieldTypeForField(first_field, pass_key)
+      first_field ? GetFieldTypeForField(first_field)
                   : BubbleDialogModelHost::FieldType::kControl;
   switch (field_type) {
     case BubbleDialogModelHost::FieldType::kMenuItem:
@@ -112,10 +110,9 @@
 
 int GetDialogBottomMargins(LayoutProvider* layout_provider,
                            ui::DialogModelField* last_field,
-                           bool has_buttons,
-                           base::PassKey<ui::DialogModelHost> pass_key) {
+                           bool has_buttons) {
   const BubbleDialogModelHost::FieldType field_type =
-      last_field ? GetFieldTypeForField(last_field, pass_key)
+      last_field ? GetFieldTypeForField(last_field)
                  : BubbleDialogModelHost::FieldType::kControl;
   switch (field_type) {
     case BubbleDialogModelHost::FieldType::kMenuItem:
@@ -299,18 +296,25 @@
 
 // TODO(pbos): Migrate most code that calls contents_view_->(some View method)
 // into this class. This was done in steps to limit the size of the diff.
-class BubbleDialogModelHost::ContentsView final : public BoxLayoutView {
-  METADATA_HEADER(ContentsView, BoxLayoutView)
+class BubbleDialogModelHostContentsView final
+    : public BoxLayoutView,
+      public ui::DialogModelFieldHost {
+  METADATA_HEADER(BubbleDialogModelHostContentsView, BoxLayoutView)
 
  public:
   // TODO(pbos): Break this dependency on BubbleDialogModelHost once most of
   // OnFieldAdded etc. has moved into this class.
-  ContentsView(BubbleDialogModelHost* parent, ui::DialogModelSection* contents)
+  BubbleDialogModelHostContentsView(
+      BubbleDialogModelHost* parent,
+      ui::DialogModelSection* contents,
+      ui::ElementIdentifier initially_focused_field_id)
       : parent_(parent),
         contents_(contents),
-        on_field_added_subscription_(contents->AddOnFieldAddedCallback(
-            base::BindRepeating(&ContentsView::OnFieldAdded,
-                                base::Unretained(this)))) {
+        initially_focused_field_id_(initially_focused_field_id),
+        on_field_added_subscription_(
+            contents->AddOnFieldAddedCallback(base::BindRepeating(
+                &BubbleDialogModelHostContentsView::OnFieldAdded,
+                base::Unretained(this)))) {
     // Note that between-child spacing is manually handled using kMarginsKey.
     SetOrientation(views::BoxLayout::Orientation::kVertical);
   }
@@ -323,25 +327,29 @@
     }
   }
 
+  [[nodiscard]] base::CallbackListSubscription AddOnFieldAddedCallback(
+      base::RepeatingCallback<void(ui::DialogModelField*)> on_field_added) {
+    return on_field_added_.Add(std::move(on_field_added));
+  }
+
   // TODO(pbos): Move (most) of the host's OnFieldAdded stuff into here. If
   // anything remains try to have BubbleDialogModelHost observe it directly.
   void OnFieldAdded(ui::DialogModelField* field) {
-    CHECK(parent_);
     switch (field->type()) {
       case ui::DialogModelField::kButton:
         // TODO(pbos): Add support for buttons that are part of content area.
         NOTREACHED_NORETURN();
       case ui::DialogModelField::kParagraph:
-        AddOrUpdateParagraph(field->AsParagraph(GetPassKey()));
+        AddOrUpdateParagraph(field->AsParagraph());
         break;
       case ui::DialogModelField::kCheckbox:
-        AddOrUpdateCheckbox(field->AsCheckbox(GetPassKey()));
+        AddOrUpdateCheckbox(field->AsCheckbox());
         break;
       case ui::DialogModelField::kCombobox:
-        AddOrUpdateCombobox(field->AsCombobox(GetPassKey()));
+        AddOrUpdateCombobox(field->AsCombobox());
         break;
       case ui::DialogModelField::kMenuItem:
-        AddOrUpdateMenuItem(field->AsMenuItem(GetPassKey()));
+        AddOrUpdateMenuItem(field->AsMenuItem());
         break;
       case ui::DialogModelField::kSection:
         // TODO(pbos): Handle nested/multiple sections.
@@ -350,20 +358,20 @@
         AddOrUpdateSeparator(field);
         break;
       case ui::DialogModelField::kTextfield:
-        AddOrUpdateTextfield(field->AsTextfield(GetPassKey()));
+        AddOrUpdateTextfield(field->AsTextfield());
         break;
       case ui::DialogModelField::kCustom:
         std::unique_ptr<View> view =
-            static_cast<CustomView*>(
-                field->AsCustomField(GetPassKey())->field(GetPassKey()))
+            static_cast<BubbleDialogModelHost::CustomView*>(
+                field->AsCustomField()->field())
                 ->TransferView();
         DCHECK(view);
-        view->SetProperty(kElementIdentifierKey, field->id(GetPassKey()));
+        view->SetProperty(kElementIdentifierKey, field->id());
         DialogModelHostField info{field, view.get(), nullptr};
         AddDialogModelHostField(std::move(view), info);
         break;
     }
-    parent_->OnFieldAdded(field);
+    on_field_added_.Notify(field);
   }
 
   // TODO(pbos): Remove the need for this method by making sure the host always
@@ -380,13 +388,12 @@
     // TODO(pbos): Handle updating existing field.
 
     std::unique_ptr<View> view =
-        model_field->header(GetPassKey()).empty()
-            ? CreateViewForLabel(model_field->label(GetPassKey()))
-            : CreateViewForParagraphWithHeader(
-                  model_field->label(GetPassKey()),
-                  model_field->header(GetPassKey()));
+        model_field->header().empty()
+            ? CreateViewForLabel(model_field->label())
+            : CreateViewForParagraphWithHeader(model_field->label(),
+                                               model_field->header());
     DialogModelHostField info{model_field, view.get(), nullptr};
-    view->SetProperty(kElementIdentifierKey, model_field->id(GetPassKey()));
+    view->SetProperty(kElementIdentifierKey, model_field->id());
     AddDialogModelHostField(std::move(view), info);
   }
 
@@ -394,15 +401,13 @@
     // TODO(pbos): Handle updating existing field.
 
     std::unique_ptr<CheckboxControl> checkbox;
-    if (DialogModelLabelRequiresStyledLabel(model_field->label(GetPassKey()))) {
-      auto label = CreateStyledLabelForDialogModelLabel(
-          model_field->label(GetPassKey()));
+    if (DialogModelLabelRequiresStyledLabel(model_field->label())) {
+      auto label = CreateStyledLabelForDialogModelLabel(model_field->label());
       const int line_height = label->GetLineHeight();
       checkbox =
           std::make_unique<CheckboxControl>(std::move(label), line_height);
     } else {
-      auto label =
-          CreateLabelForDialogModelLabel(model_field->label(GetPassKey()));
+      auto label = CreateLabelForDialogModelLabel(model_field->label());
       const int line_height = label->GetLineHeight();
       checkbox =
           std::make_unique<CheckboxControl>(std::move(label), line_height);
@@ -411,7 +416,7 @@
 
     checkbox->SetCallback(base::BindRepeating(
         [](ui::DialogModelCheckbox* model_field,
-           base::PassKey<DialogModelHost> pass_key, Checkbox* checkbox,
+           base::PassKey<DialogModelFieldHost> pass_key, Checkbox* checkbox,
            const ui::Event& event) {
           model_field->OnChecked(pass_key, checkbox->GetChecked());
         },
@@ -424,13 +429,12 @@
     // TODO(pbos): Handle updating existing field.
 
     auto combobox = std::make_unique<Combobox>(model_field->combobox_model());
-    combobox->SetAccessibleName(
-        model_field->accessible_name(GetPassKey()).empty()
-            ? model_field->label(GetPassKey())
-            : model_field->accessible_name(GetPassKey()));
+    combobox->SetAccessibleName(model_field->accessible_name().empty()
+                                    ? model_field->label()
+                                    : model_field->accessible_name());
     combobox->SetCallback(base::BindRepeating(
         [](ui::DialogModelCombobox* model_field,
-           base::PassKey<DialogModelHost> pass_key,
+           base::PassKey<DialogModelFieldHost> pass_key,
            Combobox* combobox) { model_field->OnPerformAction(pass_key); },
         model_field, GetPassKey(), combobox.get()));
 
@@ -438,13 +442,14 @@
     property_changed_subscriptions_.push_back(
         combobox->AddSelectedIndexChangedCallback(base::BindRepeating(
             [](ui::DialogModelCombobox* model_field,
-               base::PassKey<DialogModelHost> pass_key, Combobox* combobox) {
+               base::PassKey<DialogModelFieldHost> pass_key,
+               Combobox* combobox) {
               model_field->OnSelectedIndexChanged(
                   pass_key, combobox->GetSelectedIndex().value());
             },
             model_field, GetPassKey(), combobox.get())));
     const gfx::FontList& font_list = combobox->GetFontList();
-    AddViewForLabelAndField(model_field, model_field->label(GetPassKey()),
+    AddViewForLabelAndField(model_field, model_field->label(),
                             std::move(combobox), font_list);
   }
 
@@ -452,17 +457,18 @@
     // TODO(pbos): Handle updating existing field.
 
     // TODO(crbug.com/1324298): Implement this for enabled items. Sorry!
-    DCHECK(!model_field->is_enabled(GetPassKey()));
+    DCHECK(!model_field->is_enabled());
 
     auto item = std::make_unique<LabelButton>(
         base::BindRepeating(
-            [](base::PassKey<ui::DialogModelHost> pass_key,
-               ui::DialogModelMenuItem* model_field, const ui::Event& event) {
+            [](ui::DialogModelMenuItem* model_field,
+               base::PassKey<DialogModelFieldHost> pass_key,
+               const ui::Event& event) {
               model_field->OnActivated(pass_key, event.flags());
             },
-            GetPassKey(), model_field),
-        model_field->label(GetPassKey()));
-    item->SetImageModel(Button::STATE_NORMAL, model_field->icon(GetPassKey()));
+            model_field, GetPassKey()),
+        model_field->label());
+    item->SetImageModel(Button::STATE_NORMAL, model_field->icon());
     // TODO(pbos): Move DISTANCE_CONTROL_LIST_VERTICAL to
     // views::LayoutProvider and replace "12" here. See below for another "12"
     // use that also needs to be replaced.
@@ -470,8 +476,8 @@
         gfx::Insets::VH(12 / 2, LayoutProvider::Get()->GetDistanceMetric(
                                     DISTANCE_BUTTON_HORIZONTAL_PADDING))));
 
-    item->SetEnabled(model_field->is_enabled(GetPassKey()));
-    item->SetProperty(kElementIdentifierKey, model_field->id(GetPassKey()));
+    item->SetEnabled(model_field->is_enabled());
+    item->SetProperty(kElementIdentifierKey, model_field->id());
 
     DialogModelHostField info{model_field, item.get(), nullptr};
     AddDialogModelHostField(std::move(item), info);
@@ -481,33 +487,31 @@
     // TODO(pbos): Support updates to the existing model.
 
     auto textfield = std::make_unique<Textfield>();
-    textfield->SetAccessibleName(
-        model_field->accessible_name(GetPassKey()).empty()
-            ? model_field->label(GetPassKey())
-            : model_field->accessible_name(GetPassKey()));
+    textfield->SetAccessibleName(model_field->accessible_name().empty()
+                                     ? model_field->label()
+                                     : model_field->accessible_name());
     textfield->SetText(model_field->text());
 
     // If this textfield is initially focused the text should be initially
     // selected as well.
     // TODO(pbos): Fix this for non-unique IDs. This should not select all text
     // for all textfields with that ID.
-    ui::ElementIdentifier initially_focused_field_id =
-        parent_->model_->initially_focused_field(GetPassKey());
-    if (initially_focused_field_id &&
-        model_field->id(GetPassKey()) == initially_focused_field_id) {
+    if (initially_focused_field_id_ &&
+        model_field->id() == initially_focused_field_id_) {
       textfield->SelectAll(true);
     }
 
     property_changed_subscriptions_.push_back(
         textfield->AddTextChangedCallback(base::BindRepeating(
             [](ui::DialogModelTextfield* model_field,
-               base::PassKey<DialogModelHost> pass_key, Textfield* textfield) {
+               base::PassKey<DialogModelFieldHost> pass_key,
+               Textfield* textfield) {
               model_field->OnTextChanged(pass_key, textfield->GetText());
             },
             model_field, GetPassKey(), textfield.get())));
 
     const gfx::FontList& font_list = textfield->GetFontList();
-    AddViewForLabelAndField(model_field, model_field->label(GetPassKey()),
+    AddViewForLabelAndField(model_field, model_field->label(),
                             std::move(textfield), font_list);
   }
 
@@ -547,7 +551,7 @@
 
   bool DialogModelLabelRequiresStyledLabel(
       const ui::DialogModelLabel& dialog_label) {
-    return !dialog_label.replacements(GetPassKey()).empty();
+    return !dialog_label.replacements().empty();
   }
 
   std::unique_ptr<View> CreateViewForLabel(
@@ -562,7 +566,7 @@
       const ui::DialogModelLabel& dialog_label) {
     DCHECK(DialogModelLabelRequiresStyledLabel(dialog_label));
     const std::vector<ui::DialogModelLabel::TextReplacement>& replacements =
-        dialog_label.replacements(GetPassKey());
+        dialog_label.replacements();
 
     // Retrieve the replacements strings to create the text.
     std::vector<std::u16string> string_replacements;
@@ -571,11 +575,11 @@
     }
     std::vector<size_t> offsets;
     const std::u16string text = l10n_util::GetStringFUTF16(
-        dialog_label.message_id(GetPassKey()), string_replacements, &offsets);
+        dialog_label.message_id(), string_replacements, &offsets);
 
     auto styled_label = std::make_unique<StyledLabel>();
     styled_label->SetText(text);
-    styled_label->SetDefaultTextStyle(dialog_label.is_secondary(GetPassKey())
+    styled_label->SetDefaultTextStyle(dialog_label.is_secondary()
                                           ? style::STYLE_SECONDARY
                                           : style::STYLE_PRIMARY);
 
@@ -610,9 +614,9 @@
     DCHECK(!DialogModelLabelRequiresStyledLabel(dialog_label));
 
     auto text_label = std::make_unique<Label>(
-        dialog_label.GetString(GetPassKey()), style::CONTEXT_DIALOG_BODY_TEXT,
-        dialog_label.is_secondary(GetPassKey()) ? style::STYLE_SECONDARY
-                                                : style::STYLE_PRIMARY);
+        dialog_label.GetString(), style::CONTEXT_DIALOG_BODY_TEXT,
+        dialog_label.is_secondary() ? style::STYLE_SECONDARY
+                                    : style::STYLE_PRIMARY);
     text_label->SetMultiLine(true);
     text_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
     return text_label;
@@ -666,9 +670,9 @@
     fields_.push_back(field_view_info);
     View* const target = GetTargetView(field_view_info);
     target->SetProperty(kElementIdentifierKey,
-                        field_view_info.dialog_model_field->id(GetPassKey()));
+                        field_view_info.dialog_model_field->id());
     for (const auto& accelerator :
-         field_view_info.dialog_model_field->accelerators(GetPassKey())) {
+         field_view_info.dialog_model_field->accelerators()) {
       target->AddAccelerator(accelerator);
     }
   }
@@ -699,10 +703,14 @@
   // destroyed inside DestroyRootView in ~Widget.
   raw_ptr<BubbleDialogModelHost> parent_;
   raw_ptr<ui::DialogModelSection> contents_;
+  const ui::ElementIdentifier initially_focused_field_id_;
 
   const base::CallbackListSubscription on_field_added_subscription_;
 
   std::vector<DialogModelHostField> fields_;
+  // TODO(pbos): Try to work away this list (and just have the parent observe
+  // size changes).
+  base::RepeatingCallbackList<void(ui::DialogModelField*)> on_field_added_;
 
   std::vector<base::CallbackListSubscription> property_changed_subscriptions_;
 
@@ -710,12 +718,12 @@
   LayoutConsensusGroup textfield_second_column_group_;
 };
 
-BEGIN_METADATA(BubbleDialogModelHost, ContentsView, BoxLayoutView)
+BEGIN_METADATA(BubbleDialogModelHostContentsView, BoxLayoutView)
 END_METADATA
 
 BubbleDialogModelHost::ThemeChangedObserver::ThemeChangedObserver(
     BubbleDialogModelHost* parent,
-    ContentsView* contents_view)
+    BubbleDialogModelHostContentsView* contents_view)
     : parent_(parent) {
   observation_.Observe(contents_view);
 }
@@ -747,75 +755,76 @@
       // uses IsModalDialog().
       contents_view_(
           (SetModalType(modal_type), InitContentsView(model_->contents()))),
+      on_field_added_subscription_(contents_view_->AddOnFieldAddedCallback(
+          base::BindRepeating(&BubbleDialogModelHost::OnFieldAdded,
+                              base::Unretained(this)))),
       theme_observer_(this, contents_view_) {
-  model_->set_host(GetPassKey(), this);
+  model_->set_host(DialogModelHost::GetPassKey(), this);
 
   // Dialog callbacks can safely refer to |model_|, they can't be called after
   // Widget::Close() calls WidgetWillClose() synchronously so there shouldn't
   // be any dangling references after model removal.
-  SetAcceptCallbackWithClose(
-      base::BindRepeating(&ui::DialogModel::OnDialogAcceptAction,
-                          base::Unretained(model_.get()), GetPassKey()));
-  SetCancelCallbackWithClose(
-      base::BindRepeating(&ui::DialogModel::OnDialogCancelAction,
-                          base::Unretained(model_.get()), GetPassKey()));
+  SetAcceptCallbackWithClose(base::BindRepeating(
+      &ui::DialogModel::OnDialogAcceptAction, base::Unretained(model_.get()),
+      DialogModelHost::GetPassKey()));
+  SetCancelCallbackWithClose(base::BindRepeating(
+      &ui::DialogModel::OnDialogCancelAction, base::Unretained(model_.get()),
+      DialogModelHost::GetPassKey()));
   SetCloseCallback(base::BindOnce(&ui::DialogModel::OnDialogCloseAction,
                                   base::Unretained(model_.get()),
-                                  GetPassKey()));
+                                  DialogModelHost::GetPassKey()));
 
   // WindowClosingCallback happens on native widget destruction which is after
-  // |model_| reset. Hence routing this callback through |this| so that we only
-  // forward the call to DialogModel::OnWindowClosing if we haven't already been
-  // closed.
+  // |model_| reset. Hence routing this callback through |this| so that we
+  // only forward the call to DialogModel::OnWindowClosing if we haven't
+  // already been closed.
   RegisterWindowClosingCallback(base::BindOnce(
       &BubbleDialogModelHost::OnWindowClosing, base::Unretained(this)));
 
   int button_mask = ui::DIALOG_BUTTON_NONE;
-  auto* ok_button = model_->ok_button(GetPassKey());
+  auto* ok_button = model_->ok_button(DialogModelHost::GetPassKey());
   if (ok_button) {
     button_mask |= ui::DIALOG_BUTTON_OK;
-    if (!ok_button->label(GetPassKey()).empty()) {
-      SetButtonLabel(ui::DIALOG_BUTTON_OK, ok_button->label(GetPassKey()));
+    if (!ok_button->label().empty()) {
+      SetButtonLabel(ui::DIALOG_BUTTON_OK, ok_button->label());
     }
-    if (ok_button->style(GetPassKey())) {
-      SetButtonStyle(ui::DIALOG_BUTTON_OK, ok_button->style(GetPassKey()));
+    if (ok_button->style()) {
+      SetButtonStyle(ui::DIALOG_BUTTON_OK, ok_button->style());
     }
-    SetButtonEnabled(ui::DIALOG_BUTTON_OK, ok_button->is_enabled(GetPassKey()));
+    SetButtonEnabled(ui::DIALOG_BUTTON_OK, ok_button->is_enabled());
   }
 
-  auto* cancel_button = model_->cancel_button(GetPassKey());
+  auto* cancel_button = model_->cancel_button(DialogModelHost::GetPassKey());
   if (cancel_button) {
     button_mask |= ui::DIALOG_BUTTON_CANCEL;
-    if (!cancel_button->label(GetPassKey()).empty()) {
-      SetButtonLabel(ui::DIALOG_BUTTON_CANCEL,
-                     cancel_button->label(GetPassKey()));
+    if (!cancel_button->label().empty()) {
+      SetButtonLabel(ui::DIALOG_BUTTON_CANCEL, cancel_button->label());
     }
-    if (cancel_button->style(GetPassKey())) {
-      SetButtonStyle(ui::DIALOG_BUTTON_CANCEL,
-                     cancel_button->style(GetPassKey()));
+    if (cancel_button->style()) {
+      SetButtonStyle(ui::DIALOG_BUTTON_CANCEL, cancel_button->style());
     }
-    SetButtonEnabled(ui::DIALOG_BUTTON_CANCEL,
-                     cancel_button->is_enabled(GetPassKey()));
+    SetButtonEnabled(ui::DIALOG_BUTTON_CANCEL, cancel_button->is_enabled());
   }
 
-  // TODO(pbos): Consider refactoring ::SetExtraView() so it can be called after
-  // the Widget is created and still be picked up. Moving this to
+  // TODO(pbos): Consider refactoring ::SetExtraView() so it can be called
+  // after the Widget is created and still be picked up. Moving this to
   // OnWidgetInitialized() will not work until then.
   if (ui::DialogModelButton* extra_button =
-          model_->extra_button(GetPassKey())) {
-    DCHECK(!model_->extra_link(GetPassKey()));
+          model_->extra_button(DialogModelHost::GetPassKey())) {
+    DCHECK(!model_->extra_link(DialogModelHost::GetPassKey()));
     auto builder = views::Builder<MdTextButton>()
                        .SetCallback(base::BindRepeating(
                            &ui::DialogModelButton::OnPressed,
-                           base::Unretained(extra_button), GetPassKey()))
-                       .SetText(extra_button->label(GetPassKey()));
-    if (extra_button->style(GetPassKey())) {
-      builder.SetStyle(extra_button->style(GetPassKey()).value());
+                           base::Unretained(extra_button),
+                           DialogModelFieldHost::GetPassKey()))
+                       .SetText(extra_button->label());
+    if (extra_button->style()) {
+      builder.SetStyle(extra_button->style().value());
     }
-    builder.SetEnabled(extra_button->is_enabled(GetPassKey()));
+    builder.SetEnabled(extra_button->is_enabled());
     SetExtraView(std::move(builder).Build());
   } else if (ui::DialogModelLabel::TextReplacement* extra_link =
-                 model_->extra_link(GetPassKey())) {
+                 model_->extra_link(DialogModelHost::GetPassKey())) {
     DCHECK(extra_link->callback().has_value());
     auto link = std::make_unique<views::Link>(extra_link->text());
     link->SetCallback(extra_link->callback().value());
@@ -824,32 +833,36 @@
 
   SetButtons(button_mask);
 
-  if (model_->override_default_button(GetPassKey()))
-    SetDefaultButton(model_->override_default_button(GetPassKey()).value());
-
-  SetTitle(model_->title(GetPassKey()));
-
-  if (!model_->accessible_title(GetPassKey()).empty()) {
-    SetAccessibleTitle(model_->accessible_title(GetPassKey()));
+  if (model_->override_default_button(DialogModelHost::GetPassKey())) {
+    SetDefaultButton(
+        model_->override_default_button(DialogModelHost::GetPassKey()).value());
   }
 
-  SetSubtitle(model_->subtitle(GetPassKey()));
+  SetTitle(model_->title(DialogModelHost::GetPassKey()));
 
-  if (!model_->main_image(GetPassKey()).IsEmpty())
-    SetMainImage(model_->main_image(GetPassKey()));
+  if (!model_->accessible_title(DialogModelHost::GetPassKey()).empty()) {
+    SetAccessibleTitle(model_->accessible_title(DialogModelHost::GetPassKey()));
+  }
 
-  if (model_->override_show_close_button(GetPassKey())) {
-    SetShowCloseButton(*model_->override_show_close_button(GetPassKey()));
+  SetSubtitle(model_->subtitle(DialogModelHost::GetPassKey()));
+
+  if (!model_->main_image(DialogModelHost::GetPassKey()).IsEmpty()) {
+    SetMainImage(model_->main_image(DialogModelHost::GetPassKey()));
+  }
+
+  if (model_->override_show_close_button(DialogModelHost::GetPassKey())) {
+    SetShowCloseButton(
+        *model_->override_show_close_button(DialogModelHost::GetPassKey()));
   } else {
     SetShowCloseButton(!IsModalDialog());
   }
 
-  if (!model_->icon(GetPassKey()).IsEmpty()) {
-    SetIcon(model_->icon(GetPassKey()));
+  if (!model_->icon(DialogModelHost::GetPassKey()).IsEmpty()) {
+    SetIcon(model_->icon(DialogModelHost::GetPassKey()));
     SetShowIcon(true);
   }
 
-  if (model_->is_alert_dialog(GetPassKey())) {
+  if (model_->is_alert_dialog(DialogModelHost::GetPassKey())) {
 #if BUILDFLAG(IS_WIN)
     // This is taken from LocationBarBubbleDelegateView. See
     // GetAccessibleRoleForReason(). crbug.com/1125118: Windows ATs only
@@ -864,9 +877,10 @@
 #endif
   }
 
-  set_internal_name(model_->internal_name(GetPassKey()));
+  set_internal_name(model_->internal_name(DialogModelHost::GetPassKey()));
 
-  set_close_on_deactivate(model_->close_on_deactivate(GetPassKey()));
+  set_close_on_deactivate(
+      model_->close_on_deactivate(DialogModelHost::GetPassKey()));
 
   // TODO(pbos): Reconsider this for dialogs which have no actions (look like
   // menus). This is probably too wide for the TabGroupEditorBubbleView which is
@@ -907,7 +921,7 @@
   // TODO(pbos): Reconsider the uniqueness requirement, maybe this should select
   // the first one? If so add corresponding GetFirst query to DialogModel.
   ui::ElementIdentifier unique_id =
-      model_->initially_focused_field(GetPassKey());
+      model_->initially_focused_field(DialogModelHost::GetPassKey());
 
   if (!unique_id)
     return BubbleDialogDelegate::GetInitiallyFocusedView();
@@ -920,24 +934,28 @@
   // Dialog buttons are added on dialog initialization.
   if (GetOkButton()) {
     contents_view_->AddDialogModelHostFieldForExistingView(
-        {model_->ok_button(GetPassKey()), GetOkButton(), nullptr});
+        {model_->ok_button(DialogModelHost::GetPassKey()), GetOkButton(),
+         nullptr});
   }
 
   if (GetCancelButton()) {
     contents_view_->AddDialogModelHostFieldForExistingView(
-        {model_->cancel_button(GetPassKey()), GetCancelButton(), nullptr});
+        {model_->cancel_button(DialogModelHost::GetPassKey()),
+         GetCancelButton(), nullptr});
   }
 
-  if (model_->extra_button(GetPassKey())) {
+  if (model_->extra_button(DialogModelHost::GetPassKey())) {
     DCHECK(GetExtraView());
     contents_view_->AddDialogModelHostFieldForExistingView(
-        {model_->extra_button(GetPassKey()), GetExtraView(), nullptr});
+        {model_->extra_button(DialogModelHost::GetPassKey()), GetExtraView(),
+         nullptr});
   }
 
-  if (const ui::ImageModel& banner = model_->banner(GetPassKey());
+  if (const ui::ImageModel& banner =
+          model_->banner(DialogModelHost::GetPassKey());
       !banner.IsEmpty()) {
     const ui::ImageModel& dark_mode_banner =
-        model_->dark_mode_banner(GetPassKey());
+        model_->dark_mode_banner(DialogModelHost::GetPassKey());
     auto banner_view = std::make_unique<ThemeTrackingImageView>(
         banner.Rasterize(contents_view_->GetColorProvider()),
         (dark_mode_banner.IsEmpty() ? banner : dark_mode_banner)
@@ -965,7 +983,7 @@
 
   // Notify the model of window closing before destroying it (as if
   // Widget::Close)
-  model_->OnDialogDestroying(GetPassKey());
+  model_->OnDialogDestroying(DialogModelHost::GetPassKey());
 
   // Detach ContentsView as it's referring to state that's about to be
   // destroyed.
@@ -973,12 +991,14 @@
   model_.reset();
 }
 
-BubbleDialogModelHost::ContentsView* BubbleDialogModelHost::InitContentsView(
+BubbleDialogModelHostContentsView* BubbleDialogModelHost::InitContentsView(
     ui::DialogModelSection* contents) {
   auto contents_view_unique =
-      std::make_unique<BubbleDialogModelHost::ContentsView>(this, contents);
+      std::make_unique<BubbleDialogModelHostContentsView>(
+          this, contents,
+          model_->initially_focused_field(DialogModelHost::GetPassKey()));
 
-  BubbleDialogModelHost::ContentsView* const contents_view =
+  BubbleDialogModelHostContentsView* const contents_view =
       contents_view_unique.get();
 
   if (IsModalDialog()) {
@@ -1012,9 +1032,13 @@
   return contents_view;
 }
 
+// TODO(pbos): Try to remove this parameter and have a more-generic
+// OnContentsViewChanged. Maybe this doesn't even need to get communicated from
+// ContentsView but can be a ViewObserver for when the preferred size changes.
 void BubbleDialogModelHost::OnFieldAdded(ui::DialogModelField* field) {
   UpdateSpacingAndMargins();
 
+  // TODO(pbos): This should move into BubbleDialogModelHostContentsView.
   UpdateFieldVisibility(field);
 
   if (GetBubbleFrameView())
@@ -1024,10 +1048,12 @@
 void BubbleDialogModelHost::OnFieldChanged(ui::DialogModelField* field) {
   CHECK(field);
 
+  // TODO(pbos): This should move into BubbleDialogModelHostContentsView.
   UpdateFieldVisibility(field);
 
+  // TODO(pbos): This should be directly observed from DialogModel.
   if (field->type() == ui::DialogModelField::kButton) {
-    UpdateButton(field->AsButton(GetPassKey()));
+    UpdateButton(field->AsButton());
   }
 
   // If the contents of the dialog change (text, field visitiblity, etc.), the
@@ -1039,12 +1065,13 @@
   if (!ShouldShowWindowIcon()) {
     return;
   }
-  const ui::ImageModel dark_mode_icon = model_->dark_mode_icon(GetPassKey());
+  const ui::ImageModel dark_mode_icon =
+      model_->dark_mode_icon(DialogModelHost::GetPassKey());
   if (!dark_mode_icon.IsEmpty() && color_utils::IsDark(GetBackgroundColor())) {
     SetIcon(dark_mode_icon);
     return;
   }
-  SetIcon(model_->icon(GetPassKey()));
+  SetIcon(model_->icon(DialogModelHost::GetPassKey()));
 }
 
 void BubbleDialogModelHost::UpdateSpacingAndMargins() {
@@ -1076,7 +1103,7 @@
     ui::DialogModelField* const field =
         contents_view_->FindDialogModelHostField(view).dialog_model_field;
 
-    FieldType field_type = GetFieldTypeForField(field, GetPassKey());
+    const FieldType field_type = GetFieldTypeForField(field);
 
     gfx::Insets side_insets =
         field_type == FieldType::kMenuItem ? gfx::Insets() : dialog_side_insets;
@@ -1087,8 +1114,7 @@
     } else {
       DCHECK(last_field);
 
-      FieldType last_field_type =
-          GetFieldTypeForField(last_field, GetPassKey());
+      const FieldType last_field_type = GetFieldTypeForField(last_field);
       side_insets.set_top(
           GetFieldTopMargin(layout_provider, field_type, last_field_type));
       view->SetProperty(kMarginsKey, side_insets);
@@ -1103,12 +1129,10 @@
   // view directly supports a scroll view.
   const int extra_margin = scroll_view ? kScrollViewVerticalMargin : 0;
   const int top_margin =
-      GetDialogTopMargins(layout_provider, first_field, GetPassKey()) -
-      extra_margin;
+      GetDialogTopMargins(layout_provider, first_field) - extra_margin;
   const int bottom_margin =
       GetDialogBottomMargins(layout_provider, last_field,
-                             GetDialogButtons() != ui::DIALOG_BUTTON_NONE,
-                             GetPassKey()) -
+                             GetDialogButtons() != ui::DIALOG_BUTTON_NONE) -
       extra_margin;
   set_margins(gfx::Insets::TLBR(top_margin >= 0 ? top_margin : 0, 0,
                                 bottom_margin >= 0 ? bottom_margin : 0, 0));
@@ -1128,17 +1152,19 @@
   // ::Close() stack.
   if (!model_)
     return;
-  model_->OnDialogDestroying(GetPassKey());
+  model_->OnDialogDestroying(DialogModelHost::GetPassKey());
   // TODO(pbos): Do we need to reset `model_` and destroy contents? See Close().
 }
 
 void BubbleDialogModelHost::UpdateButton(ui::DialogModelButton* model_field) {
-  std::u16string label = model_field->label(GetPassKey());
-  if (model_field == model_->ok_button(GetPassKey())) {
+  std::u16string label = model_field->label();
+  if (model_field == model_->ok_button(DialogModelHost::GetPassKey())) {
     SetButtonLabel(ui::DIALOG_BUTTON_OK, label);
-  } else if (model_field == model_->cancel_button(GetPassKey())) {
+  } else if (model_field ==
+             model_->cancel_button(DialogModelHost::GetPassKey())) {
     SetButtonLabel(ui::DIALOG_BUTTON_CANCEL, label);
-  } else if (model_field == model_->extra_button(GetPassKey())) {
+  } else if (model_field ==
+             model_->extra_button(DialogModelHost::GetPassKey())) {
     static_cast<MdTextButton*>(
         GetTargetView(contents_view_->FindDialogModelHostField(model_field)))
         ->SetText(label);
diff --git a/ui/views/bubble/bubble_dialog_model_host.h b/ui/views/bubble/bubble_dialog_model_host.h
index 23ee15e..0b79f372 100644
--- a/ui/views/bubble/bubble_dialog_model_host.h
+++ b/ui/views/bubble/bubble_dialog_model_host.h
@@ -17,6 +17,10 @@
 
 namespace views {
 
+// TODO(pbos): Find a better name and move to a file separate from
+// BubbleDialogModelHost.
+class BubbleDialogModelHostContentsView;
+
 // BubbleDialogModelHost is a views implementation of ui::DialogModelHost which
 // hosts a ui::DialogModel as a BubbleDialogDelegate. This exposes such as
 // SetAnchorView(), SetArrow() and SetHighlightedButton(). For methods that are
@@ -26,12 +30,11 @@
 // ui::DialogModelHost through DialogModel::host(). This helps minimize
 // platform-specific code from platform-agnostic model-delegate code.
 class VIEWS_EXPORT BubbleDialogModelHost : public BubbleDialogDelegate,
-                                           public ui::DialogModelHost {
+                                           public ui::DialogModelHost,
+                                           public ui::DialogModelFieldHost {
  public:
   enum class FieldType { kText, kControl, kMenuItem };
 
-  class ContentsView;
-
   class VIEWS_EXPORT CustomView : public ui::DialogModelCustomField::Field {
    public:
     CustomView(std::unique_ptr<View> view, FieldType field_type);
@@ -89,7 +92,7 @@
   class ThemeChangedObserver : public ViewObserver {
    public:
     ThemeChangedObserver(BubbleDialogModelHost* parent,
-                         ContentsView* contents_view);
+                         BubbleDialogModelHostContentsView* contents_view);
     ThemeChangedObserver(const ThemeChangedObserver&) = delete;
     ThemeChangedObserver& operator=(const ThemeChangedObserver&) = delete;
     ~ThemeChangedObserver() override;
@@ -102,7 +105,7 @@
     base::ScopedObservation<View, ViewObserver> observation_{this};
   };
 
-  [[nodiscard]] ContentsView* InitContentsView(
+  [[nodiscard]] BubbleDialogModelHostContentsView* InitContentsView(
       ui::DialogModelSection* contents);
 
   void OnFieldAdded(ui::DialogModelField* field);
@@ -118,7 +121,8 @@
   bool IsModalDialog() const;
 
   std::unique_ptr<ui::DialogModel> model_;
-  const raw_ptr<ContentsView> contents_view_;
+  const raw_ptr<BubbleDialogModelHostContentsView> contents_view_;
+  base::CallbackListSubscription on_field_added_subscription_;
   ThemeChangedObserver theme_observer_;
 };
 
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index 40300f2..1f13ff1 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -1998,42 +1998,25 @@
 
 #if BUILDFLAG(IS_CHROMEOS)
 gfx::Range Textfield::GetAutocorrectRange() const {
-  return model_->autocorrect_range();
+  // TODO(b/316461955): Implement autocorrect UI for native fields.
+  NOTIMPLEMENTED_LOG_ONCE();
+  return gfx::Range();
 }
 
 gfx::Rect Textfield::GetAutocorrectCharacterBounds() const {
-  gfx::Range autocorrect_range = model_->autocorrect_range();
-  if (autocorrect_range.is_empty())
-    return gfx::Rect();
-
-  gfx::RenderText* render_text = GetRenderText();
-  const gfx::SelectionModel caret(autocorrect_range, gfx::CURSOR_BACKWARD);
-  gfx::Rect rect;
-  rect = render_text->GetCursorBounds(caret, false);
-
-  ConvertRectToScreen(this, &rect);
-  return rect;
+  // TODO(b/316461955): Implement autocorrect UI for native fields.
+  NOTIMPLEMENTED_LOG_ONCE();
+  return gfx::Rect();
 }
 
 bool Textfield::SetAutocorrectRange(const gfx::Range& range) {
   if (!range.is_empty()) {
     base::UmaHistogramEnumeration("InputMethod.Assistive.Autocorrect.Count",
                                   TextInputClient::SubClass::kTextField);
-
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-    auto* input_method_manager = ash::input_method::InputMethodManager::Get();
-    if (input_method_manager &&
-        ash::extension_ime_util::IsExperimentalMultilingual(
-            input_method_manager->GetActiveIMEState()
-                ->GetCurrentInputMethod()
-                .id())) {
-      base::UmaHistogramEnumeration(
-          "InputMethod.MultilingualExperiment.Autocorrect.Count",
-          TextInputClient::SubClass::kTextField);
-    }
-#endif
   }
-  return model_->SetAutocorrectRange(range);
+  // TODO(b/316461955): Implement autocorrect UI for native fields.
+  NOTIMPLEMENTED_LOG_ONCE();
+  return false;
 }
 
 bool Textfield::AddGrammarFragments(
diff --git a/ui/views/controls/textfield/textfield_model.cc b/ui/views/controls/textfield/textfield_model.cc
index 21f8a34..650b6a02 100644
--- a/ui/views/controls/textfield/textfield_model.cc
+++ b/ui/views/controls/textfield/textfield_model.cc
@@ -762,21 +762,6 @@
   }
 }
 
-#if BUILDFLAG(IS_CHROMEOS)
-bool TextfieldModel::SetAutocorrectRange(const gfx::Range& range) {
-  if (range.GetMax() > render_text()->text().length()) {
-    return false;
-  }
-  autocorrect_range_ = range;
-
-  // TODO(b/161490813): Update |autocorrect_range_| and show underline.
-  //  Autocorrect range needs to be updated based on user text inputs and an
-  //  underline should be shown for the range.
-  NOTIMPLEMENTED_LOG_ONCE();
-  return false;
-}
-#endif
-
 void TextfieldModel::SetCompositionFromExistingText(const gfx::Range& range) {
   if (range.is_empty() || !gfx::Range(0, text().length()).Contains(range)) {
     ClearComposition();
diff --git a/ui/views/controls/textfield/textfield_model.h b/ui/views/controls/textfield/textfield_model.h
index 5c37283..b4760fe 100644
--- a/ui/views/controls/textfield/textfield_model.h
+++ b/ui/views/controls/textfield/textfield_model.h
@@ -239,16 +239,6 @@
   // composition text.
   void SetCompositionText(const ui::CompositionText& composition);
 
-#if BUILDFLAG(IS_CHROMEOS)
-  // Return the text range corresponding to the autocorrected text.
-  const gfx::Range& autocorrect_range() const { return autocorrect_range_; }
-
-  // Sets the autocorrect range to |range|. If |range| is empty, then the
-  // autocorrect range is cleared. Returns true if the range was set or cleared
-  // successfully.
-  bool SetAutocorrectRange(const gfx::Range& range);
-#endif
-
   // Puts the text in the specified range into composition mode.
   // This method should not be called with composition text or an invalid range.
   // The provided range is checked against the string's length, if |range| is
@@ -340,10 +330,6 @@
 
   gfx::Range composition_range_;
 
-#if BUILDFLAG(IS_CHROMEOS)
-  gfx::Range autocorrect_range_;
-#endif
-
   // The list of Edits. The oldest Edits are at the front of the list, and the
   // newest ones are at the back of the list.
   using EditHistory = std::list<std::unique_ptr<internal::Edit>>;
diff --git a/ui/views/controls/textfield/textfield_unittest.cc b/ui/views/controls/textfield/textfield_unittest.cc
index 4d88615f..269eb44 100644
--- a/ui/views/controls/textfield/textfield_unittest.cc
+++ b/ui/views/controls/textfield/textfield_unittest.cc
@@ -3373,75 +3373,6 @@
   // - rects[6] == rects[7]
 }
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-TEST_F(TextfieldTest, SetAutocorrectRange) {
-  InitTextfield();
-
-  textfield_->SetText(u"abc def ghi");
-  textfield_->SetAutocorrectRange(gfx::Range(4, 7));
-
-  gfx::Range autocorrect_range = textfield_->GetAutocorrectRange();
-  EXPECT_EQ(autocorrect_range, gfx::Range(4, 7));
-}
-
-TEST_F(TextfieldTest, DoesNotSetAutocorrectRangeWhenRangeGivenIsInvalid) {
-  InitTextfield();
-
-  textfield_->SetText(u"abc");
-
-  EXPECT_FALSE(textfield_->SetAutocorrectRange(gfx::Range(8, 11)));
-  EXPECT_TRUE(textfield_->GetAutocorrectRange().is_empty());
-}
-
-TEST_F(TextfieldTest,
-       ClearsAutocorrectRangeWhenSetAutocorrectRangeWithEmptyRange) {
-  InitTextfield();
-
-  textfield_->SetText(u"abc");
-
-  // TODO(b/161490813): Change to EXPECT_TRUE after fixing set range.
-  EXPECT_FALSE(textfield_->SetAutocorrectRange(gfx::Range()));
-  EXPECT_TRUE(textfield_->GetAutocorrectRange().is_empty());
-}
-
-TEST_F(TextfieldTest, GetAutocorrectCharacterBoundsTest) {
-  InitTextfield();
-
-  textfield_->InsertText(
-      u"hello placeholder text",
-      ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
-  textfield_->SetAutocorrectRange(gfx::Range(3, 10));
-
-  EXPECT_EQ(textfield_->GetAutocorrectRange(), gfx::Range(3, 10));
-
-  gfx::Rect rect_for_long_text = textfield_->GetAutocorrectCharacterBounds();
-
-  textfield_->clear();
-
-  textfield_->InsertText(
-      u"hello placeholder text",
-      ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
-  textfield_->SetAutocorrectRange(gfx::Range(3, 8));
-
-  EXPECT_EQ(textfield_->GetAutocorrectRange(), gfx::Range(3, 8));
-
-  gfx::Rect rect_for_short_text = textfield_->GetAutocorrectCharacterBounds();
-
-  EXPECT_LT(rect_for_short_text.x(), rect_for_long_text.x());
-  EXPECT_EQ(rect_for_short_text.y(), rect_for_long_text.y());
-  EXPECT_EQ(rect_for_short_text.height(), rect_for_long_text.height());
-  // TODO(crbug.com/1108170): Investigate why the rectangle width is wrong.
-  // The value seems to be wrong due to the incorrect value being returned from
-  // RenderText::GetCursorBounds(). Unfortuantly, that is tricky to fix, since
-  // RenderText is used in other parts of the codebase.
-  // When fixed, the following EXPECT statement should pass.
-  // EXPECT_LT(rect_for_short_text.width(), rect_for_long_text.width());
-}
-
-// TODO(crbug.com/1108170): Add a test to check that when the composition /
-// surrounding text is updated, the AutocorrectRange is updated accordingly.
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
 // The word we select by double clicking should remain selected regardless of
 // where we drag the mouse afterwards without releasing the left button.
 TEST_F(TextfieldTest, KeepInitiallySelectedWord) {
diff --git a/ui/webui/resources/cr_components/app_management/supported_links_dialog.ts b/ui/webui/resources/cr_components/app_management/supported_links_dialog.ts
index fe404896..6adbde3 100644
--- a/ui/webui/resources/cr_components/app_management/supported_links_dialog.ts
+++ b/ui/webui/resources/cr_components/app_management/supported_links_dialog.ts
@@ -6,6 +6,7 @@
 import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js';
 import 'chrome://resources/polymer/v3_0/iron-list/iron-list.js';
 
+import {CrIconButtonElement} from 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js';
 import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
@@ -31,6 +32,27 @@
   }
 
   app: App;
+
+  override ready() {
+    super.ready();
+    this.addEventListener(
+        'keydown', e => this.trapDialogFocus_(e as KeyboardEvent));
+  }
+
+  // The close button is the only tabbable element in the dialog, so focus
+  // should stay on it.
+  private trapDialogFocus_(e: KeyboardEvent) {
+    if (e.key === 'Tab') {
+      e.preventDefault();
+      const dialogElement = this.shadowRoot?.getElementById('dialog');
+      const buttonElement =
+          dialogElement?.shadowRoot?.querySelector<CrIconButtonElement>(
+              '#close');
+      if (buttonElement) {
+        buttonElement.focus();
+      }
+    }
+  }
 }
 
 declare global {
diff --git a/v8 b/v8
index b8c5311..457c0cb 160000
--- a/v8
+++ b/v8
@@ -1 +1 @@
-Subproject commit b8c5311b4088a044fc167fa2bf270fbdabf324e6
+Subproject commit 457c0cbb2f97c9a56941eb48b95e0234d0739cd3