diff --git a/DEPS b/DEPS
index 3379ba6..f6eb34f 100644
--- a/DEPS
+++ b/DEPS
@@ -250,7 +250,7 @@
   # luci-go CIPD package version.
   # Make sure the revision is uploaded by infra-packagers builder.
   # https://ci.chromium.org/p/infra-internal/g/infra-packagers/console
-  'luci_go': 'git_revision:05765dd1fd00909347fcc36cac12b732e3039e3d',
+  'luci_go': 'git_revision:9f65ffe719f73af390727d369b342c22fa37ea54',
 
   # This can be overridden, e.g. with custom_vars, to build clang from HEAD
   # instead of downloading the prebuilt pinned revision.
@@ -311,7 +311,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': '2b0be936426d7226ec71be4048e5192963d31062',
+  'v8_revision': 'bdffe700b0df8e35002a89101e3286c83728a6cb',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
@@ -323,7 +323,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '820c7b4184d0b1849365f221e9c1e0660664434a',
+  'pdfium_revision': '9d2c662f557544e5edb74a60b52fb297f4c5dfee',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -378,7 +378,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': 'e9d00911512b1412c72eda19785a332ae13cfa69',
+  'catapult_revision': '9b0585389e2e19739ed3492415f8ded3f771b754',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -422,7 +422,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': 'ba384f0383502bb182f810c3007235a6d0aadc3f',
+  'dawn_revision': 'bcbe527ecb670ffa35105fa82a1ae62a0e439ba9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -466,7 +466,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':    '849e53c238d1bb46f9fca95ae57d539559564596',
+  'libcxxabi_revision':    '9572e56a12c88c011d504a707ca94952be4664f9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -818,7 +818,7 @@
 
   'src/clank': {
     'url': 'https://chrome-internal.googlesource.com/clank/internal/apps.git' + '@' +
-    'fcea22e26c67e9b39f3f3d00810500b306722e32',
+    '130bc9859f6d8770f2406d164ed170740a765b31',
     'condition': 'checkout_android and checkout_src_internal and not checkout_clank_via_src_internal',
   },
 
@@ -1002,7 +1002,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'JAK1JohWSJjm36wDo8wmTCudJ4_FjnqO3PuS7EC2EZoC',
+          'version': 'XL-7BvEmOjk2I9PKLeYKkahaBW1iI_5O23up19pvZzwC',
       },
     ],
     'condition': 'checkout_android',
@@ -1245,7 +1245,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '67d8bcb9957d1154387c0702fd8115729f81f935',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '77355b7fe2b4a494cd785b6621d06880955c2816',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1666,7 +1666,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '4fcf7d61f3559fdb37fefda36e272f05e40f0fef',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '129b11632395a84eb3307d72fde9a90945e18619',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1811,7 +1811,7 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@cc354388a3eba2759a5158896c2ed7a433ab5884',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@6ef568a8ef04125e70096158194f5a856187cb5a',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907',
@@ -1878,7 +1878,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/linux-amd64',
-          'version': 'vMuEaxuoKcSgIEyacUY5YqByCP4RveJIid7OXrLUZnwC',
+          'version': 'N6uCjU9yuRs_YqzOLUOdwHsH-AYHQKQp4gidLlDHDesC',
         },
       ],
       'dep_type': 'cipd',
@@ -1921,7 +1921,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@b8ba6757c04ce866ecb8720119d7c3c56b5dbaf5',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@124f4110fa09abf19754c12c649ec95c82fea19b',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/WATCHLISTS b/WATCHLISTS
index 36e3e63..897c5759 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -2297,8 +2297,9 @@
     'autofill_assistant': ['autofill_assistant+watch@google.com'],
     'autofill_payments': ['armalhotra+autofillwatch@google.com',
                           'jsaul+autofillwatch@google.com',
-                          'siyua+autofillwatch@chromium.org',
-                          'siashah+autofillwatch@chromium.org'],
+                          'shgar+autofillwatch@google.com',
+                          'siashah+autofillwatch@chromium.org',
+                          'siyua+autofillwatch@chromium.org'],
     'background_fetch': ['peter@chromium.org',
                          'rayankans+watch@chromium.org',
                          'nator+watch@chromium.org'],
diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
index e50dface..ee2bff2 100644
--- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
+++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
@@ -383,6 +383,7 @@
                             + " including synchronized decoding."),
             Flag.baseFeature(BlinkFeatures.THREADED_BODY_LOADER,
                     "If enabled, reads and decodes navigation body data off the main thread."),
+            Flag.baseFeature("PreconnectOnRedirect"),
             // Add new commandline switches and features above. The final entry should have a
             // trailing comma for cleaner diffs.
     };
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index f991c4c3..d085f92 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -2327,8 +2327,6 @@
     "//ash/quick_pair/scanning",
     "//ash/quick_pair/ui",
     "//ash/services/multidevice_setup/public/mojom",
-    "//ash/services/recording",
-    "//ash/services/recording/public/mojom",
     "//ash/style",
     "//ash/system/machine_learning:user_settings_event_proto",
     "//ash/webui/diagnostics_ui/mojom:mojom",
@@ -2376,6 +2374,8 @@
     "//chromeos/ash/services/quick_pair",
     "//chromeos/ash/services/quick_pair/public/cpp",
     "//chromeos/ash/services/quick_pair/public/mojom",
+    "//chromeos/ash/services/recording",
+    "//chromeos/ash/services/recording/public/mojom",
     "//chromeos/components/quick_answers/public/cpp:prefs",
     "//chromeos/components/sensors:buildflags",
     "//chromeos/components/sensors:sensors",
@@ -2826,6 +2826,7 @@
     "shelf/test/widget_animation_smoothness_inspector.h",
     "shell_unittest.cc",
     "style/ash_color_provider_unittest.cc",
+    "style/color_util_unittest.cc",
     "style/dark_light_mode_controller_unittests.cc",
     "style/dark_light_mode_nudge_controller_unittests.cc",
     "style/system_components_unittests.cc",
@@ -3166,7 +3167,6 @@
     "//ash/services:unit_tests",
     "//ash/services/multidevice_setup/public/cpp:test_support",
     "//ash/services/multidevice_setup/public/mojom",
-    "//ash/services/recording:test_support",
     "//ash/shortcut_viewer:unit_tests",
     "//ash/strings",
     "//ash/style",
@@ -3204,6 +3204,7 @@
     "//chromeos/ash/services/assistant/public/mojom",
     "//chromeos/ash/services/bluetooth_config:test_support",
     "//chromeos/ash/services/nearby/public/cpp",
+    "//chromeos/ash/services/recording:test_support",
     "//chromeos/components/sensors:sensors",
     "//chromeos/components/sensors:test_support",
     "//chromeos/components/sensors/mojom",
@@ -3628,8 +3629,6 @@
     "//ash/public/cpp",
     "//ash/public/cpp:test_support",
     "//ash/public/cpp/ambient/proto",
-    "//ash/services/recording:test_support",
-    "//ash/services/recording/public/mojom",
     "//ash/webui/personalization_app/mojom",
     "//ash/webui/personalization_app/proto",
     "//base",
@@ -3648,6 +3647,8 @@
     "//chromeos/ash/services/assistant:test_support",
     "//chromeos/ash/services/assistant/public/cpp",
     "//chromeos/ash/services/bluetooth_config:test_support",
+    "//chromeos/ash/services/recording:test_support",
+    "//chromeos/ash/services/recording/public/mojom",
     "//chromeos/dbus/power",
     "//chromeos/dbus/power:power_manager_proto",
     "//chromeos/login/login_state",
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc
index 7c06e9bd..62a3e72 100644
--- a/ash/app_list/app_list_controller_impl.cc
+++ b/ash/app_list/app_list_controller_impl.cc
@@ -231,11 +231,6 @@
   return prefs->GetBoolean(chromeos::prefs::kSuggestedContentEnabled);
 }
 
-int GetOffset(int offset, const char* pref_name) {
-  PrefService* prefs = GetLastActiveUserPrefService();
-  return prefs->GetBoolean(pref_name) ? -offset : offset;
-}
-
 // Gets the MRU window shown over the applist when in tablet mode.
 // Returns nullptr if no windows are shown over the applist.
 aura::Window* GetTopVisibleWindow() {
@@ -547,17 +542,6 @@
                               event_time_stamp, show_source);
 }
 
-void AppListControllerImpl::ProcessMouseWheelEvent(
-    const ui::MouseWheelEvent& event) {
-  fullscreen_presenter_->ProcessMouseWheelOffset(event.location(),
-                                                 event.offset());
-}
-
-void AppListControllerImpl::ProcessScrollEvent(const ui::ScrollEvent& event) {
-  gfx::Vector2d offset(event.x_offset(), event.y_offset());
-  fullscreen_presenter_->ProcessScrollOffset(event.location(), offset);
-}
-
 void AppListControllerImpl::UpdateAppListWithNewTemporarySortOrder(
     const absl::optional<AppListSortOrder>& new_order,
     bool animate,
@@ -1543,31 +1527,6 @@
   }
 }
 
-int AppListControllerImpl::AdjustAppListViewScrollOffset(int offset,
-                                                         ui::EventType type) {
-  Shelf* shelf = Shelf::ForWindow(
-      fullscreen_presenter_->GetView()->GetWidget()->GetNativeView());
-
-  // When Natural/Reverse Scrolling is turned on, the events we receive have had
-  // their offsets inverted to make that feature work. Certain behaviors, like
-  // scrolling on the shelf to expand the app list, only make sense in their
-  // original direction, so we undo that inversion.
-  int adjusted_offset =
-      (type == ui::ET_SCROLL || type == ui::ET_SCROLL_FLING_START)
-          ? GetOffset(offset, prefs::kNaturalScroll)
-          : GetOffset(offset, prefs::kMouseReverseScroll);
-
-  // If the shelf is side mounted, we set the offset in terms of being toward
-  // the shelf to simplify the logic later.
-  if (!shelf->IsHorizontalAlignment()) {
-    adjusted_offset = shelf->alignment() == ShelfAlignment::kLeft
-                          ? adjusted_offset
-                          : -adjusted_offset;
-  }
-
-  return adjusted_offset;
-}
-
 void AppListControllerImpl::LoadIcon(const std::string& app_id) {
   if (client_)
     client_->LoadIcon(profile_id_, app_id);
diff --git a/ash/app_list/app_list_controller_impl.h b/ash/app_list/app_list_controller_impl.h
index 047ac649..f38e6ca 100644
--- a/ash/app_list/app_list_controller_impl.h
+++ b/ash/app_list/app_list_controller_impl.h
@@ -44,10 +44,6 @@
 
 class PrefRegistrySimple;
 
-namespace ui {
-class MouseWheelEvent;
-}  // namespace ui
-
 namespace ash {
 
 class AppListBadgeController;
@@ -124,8 +120,6 @@
   void Show(int64_t display_id,
             absl::optional<AppListShowSource> show_source,
             base::TimeTicks event_time_stamp);
-  void ProcessMouseWheelEvent(const ui::MouseWheelEvent& event);
-  void ProcessScrollEvent(const ui::ScrollEvent& event);
   void UpdateAppListWithNewTemporarySortOrder(
       const absl::optional<AppListSortOrder>& new_order,
       bool animate,
@@ -195,7 +189,6 @@
   void OnStateTransitionAnimationCompleted(
       AppListViewState state,
       bool was_animation_interrupted) override;
-  int AdjustAppListViewScrollOffset(int offset, ui::EventType type) override;
   void LoadIcon(const std::string& app_id) override;
   bool HasValidProfile() const override;
   bool ShouldHideContinueSection() const override;
diff --git a/ash/app_list/app_list_presenter_impl.cc b/ash/app_list/app_list_presenter_impl.cc
index 06324e7..c801b68 100644
--- a/ash/app_list/app_list_presenter_impl.cc
+++ b/ash/app_list/app_list_presenter_impl.cc
@@ -395,20 +395,6 @@
   return is_target_visibility_show_;
 }
 
-void AppListPresenterImpl::ProcessScrollOffset(
-    const gfx::Point& location,
-    const gfx::Vector2d& scroll_offset_vector) {
-  if (view_)
-    view_->HandleScroll(location, scroll_offset_vector, ui::ET_SCROLL);
-}
-
-void AppListPresenterImpl::ProcessMouseWheelOffset(
-    const gfx::Point& location,
-    const gfx::Vector2d& scroll_offset_vector) {
-  if (view_)
-    view_->HandleScroll(location, scroll_offset_vector, ui::ET_MOUSEWHEEL);
-}
-
 void AppListPresenterImpl::UpdateScaleAndOpacityForHomeLauncher(
     float scale,
     float opacity,
diff --git a/ash/app_list/app_list_presenter_impl.h b/ash/app_list/app_list_presenter_impl.h
index 08c2d1b..2955f37c 100644
--- a/ash/app_list/app_list_presenter_impl.h
+++ b/ash/app_list/app_list_presenter_impl.h
@@ -128,16 +128,6 @@
   // transition is in progress.
   bool GetTargetVisibility() const;
 
-  // Passes data from a Scroll event from the shelf to the
-  // AppListView.
-  void ProcessScrollOffset(const gfx::Point& location,
-                           const gfx::Vector2d& scroll_offset_vector);
-
-  // Passes data from a MouseWheelEvent event from the shelf to the
-  // AppListView.
-  void ProcessMouseWheelOffset(const gfx::Point& location,
-                               const gfx::Vector2d& scroll_offset_vector);
-
   // Scales the home launcher view maintaining the view center point, and
   // updates its opacity. If |callback| is non-null, the update should be
   // animated, and the |callback| should be called with the animation settings.
diff --git a/ash/app_list/app_list_test_view_delegate.cc b/ash/app_list/app_list_test_view_delegate.cc
index 75ea3ee..7aefc5f 100644
--- a/ash/app_list/app_list_test_view_delegate.cc
+++ b/ash/app_list/app_list_test_view_delegate.cc
@@ -143,11 +143,6 @@
   return 0;
 }
 
-int AppListTestViewDelegate::AdjustAppListViewScrollOffset(int offset,
-                                                           ui::EventType type) {
-  return offset;
-}
-
 bool AppListTestViewDelegate::HasValidProfile() const {
   return true;
 }
diff --git a/ash/app_list/app_list_test_view_delegate.h b/ash/app_list/app_list_test_view_delegate.h
index fda06a99..b6c6c8f 100644
--- a/ash/app_list/app_list_test_view_delegate.h
+++ b/ash/app_list/app_list_test_view_delegate.h
@@ -115,7 +115,6 @@
   bool AppListTargetVisibility() const override;
   bool IsInTabletMode() override;
   AppListNotifier* GetNotifier() override;
-  int AdjustAppListViewScrollOffset(int offset, ui::EventType type) override;
   void LoadIcon(const std::string& app_id) override {}
   bool HasValidProfile() const override;
   bool ShouldHideContinueSection() const override;
diff --git a/ash/app_list/app_list_view_delegate.h b/ash/app_list/app_list_view_delegate.h
index 64a1d54..a091a4a 100644
--- a/ash/app_list/app_list_view_delegate.h
+++ b/ash/app_list/app_list_view_delegate.h
@@ -195,10 +195,6 @@
   // Returns whether tablet mode is currently enabled.
   virtual bool IsInTabletMode() = 0;
 
-  // Adjust scrolls that happen in the view. This needs to be delegated because
-  // it depends on the active user's preferences.
-  virtual int AdjustAppListViewScrollOffset(int offset, ui::EventType type) = 0;
-
   // Loads the icon of an app item identified by `app_id`.
   virtual void LoadIcon(const std::string& app_id) = 0;
 
diff --git a/ash/app_list/views/app_list_view.cc b/ash/app_list/views/app_list_view.cc
index 09cf2ec..05da13f 100644
--- a/ash/app_list/views/app_list_view.cc
+++ b/ash/app_list/views/app_list_view.cc
@@ -938,56 +938,10 @@
   search_box_view_->OnWallpaperColorsChanged();
 }
 
-bool AppListView::ShouldScrollDismissAppList(const gfx::Point& location,
-                                             const gfx::Vector2d& offset,
-                                             ui::EventType type,
-                                             bool is_in_vertical_bounds) {
-  if (delegate_->IsInTabletMode())
-    return false;
-
-  if (GetAppsContainerView()->IsInFolderView() && is_in_vertical_bounds)
-    return false;
-
-  if (!is_side_shelf() && is_in_vertical_bounds)
-    return false;
-
-  if (is_side_shelf()) {
-    // This offset will be adjusted for scrolling preferences, as well as
-    // for shelf alignment. Positive values are toward the shelf.
-    int adjusted_offset =
-        delegate_->AdjustAppListViewScrollOffset(offset.x(), type);
-
-    // If the magnitude is big enough and the scroll is toward the shelf,
-    // dismiss the full screen AppList.
-    if (adjusted_offset > AppListView::kAppListMinScrollToSwitchStates &&
-        app_list_state_ == AppListViewState::kFullscreenAllApps) {
-      return true;
-    }
-  } else {
-    int adjusted_offset =
-        delegate_->AdjustAppListViewScrollOffset(offset.y(), type);
-
-    // If the event is a mousewheel event, the offset is always large
-    // enough, otherwise the offset must be larger than the scroll
-    // threshold to dismiss from full screen.
-    if ((type == ui::ET_MOUSEWHEEL ||
-         std::abs(adjusted_offset) >
-             AppListView::kAppListMinScrollToSwitchStates) &&
-        app_list_state_ == AppListViewState::kFullscreenAllApps &&
-        adjusted_offset < 0) {
-      return true;
-    }
-  }
-  return false;
-}
-
 bool AppListView::HandleScroll(const gfx::Point& location,
                                const gfx::Vector2d& offset,
                                ui::EventType type) {
-  // Ignore 0-offset events to prevent spurious dismissal, see crbug.com/806338
-  // The system generates 0-offset ET_SCROLL_FLING_CANCEL events during simple
-  // touchpad mouse moves. Those may be passed via mojo APIs and handled here.
-  if ((offset.y() == 0 && offset.x() == 0) || ShouldIgnoreScrollEvents())
+  if (ShouldIgnoreScrollEvents())
     return false;
 
   // Don't forward scroll information if a folder is open. The folder view will
@@ -1008,20 +962,9 @@
       root_apps_grid_location.y() > apps_grid_view->GetLocalBounds().y() &&
       root_apps_grid_location.y() < apps_grid_view->GetLocalBounds().bottom();
 
-  // First see if we need to collapse the app list from this scroll when in a
-  // side shelf alignment. We do this first because if this happens anywhere on
-  // the app list or shelf, we're going to dismiss and not scroll.
-  if (ShouldScrollDismissAppList(location, offset, type,
-                                 is_in_vertical_bounds)) {
-    Dismiss();
-    return true;
-  }
-
-  // In fullscreen, forward events to `apps_grid_view`. For example, this allows
-  // scroll events to the right of the page switcher (not inside the apps grid)
-  // to switch pages.
-  if (app_list_state_ == AppListViewState::kFullscreenAllApps &&
-      is_in_vertical_bounds) {
+  // Forward events to `apps_grid_view`. This allows scroll events to the right
+  // of the page switcher (not inside the apps grid) to switch pages.
+  if (is_in_vertical_bounds) {
     apps_grid_view->HandleScrollFromParentView(offset, type);
   }
   return true;
diff --git a/ash/app_list/views/app_list_view.h b/ash/app_list/views/app_list_view.h
index 0ab6099..c9ff9cf 100644
--- a/ash/app_list/views/app_list_view.h
+++ b/ash/app_list/views/app_list_view.h
@@ -125,9 +125,6 @@
   static constexpr int kAppListAnimationDurationMs = 200;
   static constexpr int kAppListAnimationDurationFromFullscreenMs = 250;
 
-  // The scroll offset in order to transition from PEEKING to FULLSCREEN
-  static constexpr int kAppListMinScrollToSwitchStates = 20;
-
   // Does not take ownership of |delegate|.
   explicit AppListView(AppListViewDelegate* delegate);
 
@@ -388,15 +385,6 @@
   // Returns true if scroll events should be ignored.
   bool ShouldIgnoreScrollEvents();
 
-  // Returns true if we should dismiss app list. We use the |location|,
-  // |offset|, and |type| of the scroll event. |is_in_vertical_bounds| indicates
-  // whether the event took place within the vertical bounds of the apps grid,
-  // since this affects dismissal behavior.
-  bool ShouldScrollDismissAppList(const gfx::Point& location,
-                                  const gfx::Vector2d& offset,
-                                  ui::EventType type,
-                                  bool is_in_vertical_bounds);
-
   // Returns preferred y of fullscreen widget bounds in parent window for the
   // specified state.
   int GetPreferredWidgetYForState(AppListViewState state) const;
diff --git a/ash/app_list/views/app_list_view_unittest.cc b/ash/app_list/views/app_list_view_unittest.cc
index adfe1f8..f0aa533 100644
--- a/ash/app_list/views/app_list_view_unittest.cc
+++ b/ash/app_list/views/app_list_view_unittest.cc
@@ -1407,32 +1407,6 @@
   ASSERT_EQ(ash::AppListViewState::kFullscreenAllApps, view_->app_list_state());
 }
 
-TEST_F(AppListViewPeekingTest,
-       DownwardMouseWheelScrollDismissesPeekingLauncher) {
-  Initialize(false /*is_tablet_mode*/);
-  delegate_->GetTestModel()->PopulateApps(kInitialItems);
-  Show();
-
-  EXPECT_EQ(ash::AppListViewState::kFullscreenAllApps, view_->app_list_state());
-
-  EXPECT_EQ(0, delegate_->dismiss_count());
-  view_->HandleScroll(gfx::Point(0, 0), gfx::Vector2d(0, -30),
-                      ui::ET_MOUSEWHEEL);
-  EXPECT_EQ(1, delegate_->dismiss_count());
-}
-
-TEST_F(AppListViewPeekingTest, DownwardGestureScrollDismissesPeekingLauncher) {
-  Initialize(false /*is_tablet_mode*/);
-  delegate_->GetTestModel()->PopulateApps(kInitialItems);
-  Show();
-
-  EXPECT_EQ(ash::AppListViewState::kFullscreenAllApps, view_->app_list_state());
-
-  EXPECT_EQ(0, delegate_->dismiss_count());
-  view_->HandleScroll(gfx::Point(0, 0), gfx::Vector2d(0, -30), ui::ET_SCROLL);
-  EXPECT_EQ(1, delegate_->dismiss_count());
-}
-
 // Tests that typing when in fullscreen changes the state to fullscreen search.
 TEST_F(AppListViewPeekingTest, TypingFullscreenToFullscreenSearch) {
   Initialize(false /*is_tablet_mode*/);
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 74769c8..3fdd157 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -2012,6 +2012,30 @@
       <message name="IDS_ASH_DESKS_DESK_8_MINI_VIEW_TITLE" desc="The label of the eighth virtual desk thumbnail.">
         Desk 8
       </message>
+      <message name="IDS_ASH_DESKS_DESK_9_MINI_VIEW_TITLE" desc="The label of the ninth virtual desk thumbnail.">
+        Desk 9
+      </message>
+      <message name="IDS_ASH_DESKS_DESK_10_MINI_VIEW_TITLE" desc="The label of the tenth virtual desk thumbnail.">
+        Desk 10
+      </message>
+      <message name="IDS_ASH_DESKS_DESK_11_MINI_VIEW_TITLE" desc="The label of the eleventh virtual desk thumbnail.">
+        Desk 11
+      </message>
+      <message name="IDS_ASH_DESKS_DESK_12_MINI_VIEW_TITLE" desc="The label of the twelfth virtual desk thumbnail.">
+        Desk 12
+      </message>
+      <message name="IDS_ASH_DESKS_DESK_13_MINI_VIEW_TITLE" desc="The label of the thirteenth virtual desk thumbnail.">
+        Desk 13
+      </message>
+      <message name="IDS_ASH_DESKS_DESK_14_MINI_VIEW_TITLE" desc="The label of the fourteenth virtual desk thumbnail.">
+        Desk 14
+      </message>
+      <message name="IDS_ASH_DESKS_DESK_15_MINI_VIEW_TITLE" desc="The label of the fifteenth virtual desk thumbnail.">
+        Desk 15
+      </message>
+      <message name="IDS_ASH_DESKS_DESK_16_MINI_VIEW_TITLE" desc="The label of the sixteenth virtual desk thumbnail.">
+        Desk 16
+      </message>
       <message name="IDS_ASH_DESKS_MAX_NUM_REACHED" desc="Message shown to users when they attempt to add a new virtual desk when the maximum number of desks has been reached.">
         Maximum number of desks reached.
       </message>
diff --git a/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_10_MINI_VIEW_TITLE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_10_MINI_VIEW_TITLE.png.sha1
new file mode 100644
index 0000000..6966e519
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_10_MINI_VIEW_TITLE.png.sha1
@@ -0,0 +1 @@
+5734ddc2b3616da0363ef3915f8140047c3fd679
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_11_MINI_VIEW_TITLE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_11_MINI_VIEW_TITLE.png.sha1
new file mode 100644
index 0000000..a62bd2b
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_11_MINI_VIEW_TITLE.png.sha1
@@ -0,0 +1 @@
+4b01ef86b4f18673e366f0daa288c81b24632d72
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_12_MINI_VIEW_TITLE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_12_MINI_VIEW_TITLE.png.sha1
new file mode 100644
index 0000000..bcb1d296
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_12_MINI_VIEW_TITLE.png.sha1
@@ -0,0 +1 @@
+0e20c93104f0c3f888799858ab1ac602b6fc2895
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_13_MINI_VIEW_TITLE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_13_MINI_VIEW_TITLE.png.sha1
new file mode 100644
index 0000000..5665d7f
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_13_MINI_VIEW_TITLE.png.sha1
@@ -0,0 +1 @@
+37c590fe6a4e29648d256d3d46d659fc1c39f2be
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_14_MINI_VIEW_TITLE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_14_MINI_VIEW_TITLE.png.sha1
new file mode 100644
index 0000000..89e1e49e
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_14_MINI_VIEW_TITLE.png.sha1
@@ -0,0 +1 @@
+5c910096df22f0d70a42f2932679657316c0f1ff
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_15_MINI_VIEW_TITLE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_15_MINI_VIEW_TITLE.png.sha1
new file mode 100644
index 0000000..66afb21
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_15_MINI_VIEW_TITLE.png.sha1
@@ -0,0 +1 @@
+c8e2cc7de44021c8fcba1df1f005d1e46a56996e
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_16_MINI_VIEW_TITLE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_16_MINI_VIEW_TITLE.png.sha1
new file mode 100644
index 0000000..4e1202f
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_16_MINI_VIEW_TITLE.png.sha1
@@ -0,0 +1 @@
+9746407f33db29d2cfaf7a3f2935789ccb0a55a3
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_9_MINI_VIEW_TITLE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_9_MINI_VIEW_TITLE.png.sha1
new file mode 100644
index 0000000..0bc8fb8
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_9_MINI_VIEW_TITLE.png.sha1
@@ -0,0 +1 @@
+d40bf6abd2477ead797905d83556bfc37914615b
\ No newline at end of file
diff --git a/ash/capture_mode/DEPS b/ash/capture_mode/DEPS
index 304331b..275ba7a 100644
--- a/ash/capture_mode/DEPS
+++ b/ash/capture_mode/DEPS
@@ -1,6 +1,8 @@
 include_rules = [
   "+cc/trees/layer_tree_frame_sink.h",
   "+cc/trees/layer_tree_frame_sink_client.h",
+  "+chromeos/ash/services/recording/recording_service_test_api.h",
+  "+chromeos/ash/services/recording/public/mojom",
   "+components/viz/client/client_resource_provider.h",
   "+gpu/command_buffer/client/gpu_memory_buffer_manager.h",
   "+gpu/command_buffer/client/shared_image_interface.h",
diff --git a/ash/capture_mode/capture_mode_controller.h b/ash/capture_mode/capture_mode_controller.h
index 50cfef1..c202c2023 100644
--- a/ash/capture_mode/capture_mode_controller.h
+++ b/ash/capture_mode/capture_mode_controller.h
@@ -14,7 +14,6 @@
 #include "ash/capture_mode/video_recording_watcher.h"
 #include "ash/public/cpp/capture_mode/capture_mode_delegate.h"
 #include "ash/public/cpp/session/session_observer.h"
-#include "ash/services/recording/public/mojom/recording_service.mojom.h"
 #include "base/callback_forward.h"
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted_memory.h"
@@ -22,6 +21,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
+#include "chromeos/ash/services/recording/public/mojom/recording_service.mojom.h"
 #include "chromeos/dbus/power/power_manager_client.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver.h"
diff --git a/ash/capture_mode/capture_mode_unittests.cc b/ash/capture_mode/capture_mode_unittests.cc
index c83c0833..0298ec8 100644
--- a/ash/capture_mode/capture_mode_unittests.cc
+++ b/ash/capture_mode/capture_mode_unittests.cc
@@ -50,7 +50,6 @@
 #include "ash/public/cpp/test/mock_projector_client.h"
 #include "ash/public/cpp/test/shell_test_api.h"
 #include "ash/root_window_controller.h"
-#include "ash/services/recording/recording_service_test_api.h"
 #include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/test/ash_test_base.h"
@@ -76,6 +75,7 @@
 #include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
+#include "chromeos/ash/services/recording/recording_service_test_api.h"
 #include "chromeos/dbus/power/fake_power_manager_client.h"
 #include "chromeos/dbus/power_manager/suspend.pb.h"
 #include "components/account_id/account_id.h"
diff --git a/ash/capture_mode/test_capture_mode_delegate.cc b/ash/capture_mode/test_capture_mode_delegate.cc
index 12c1701..d7fec35 100644
--- a/ash/capture_mode/test_capture_mode_delegate.cc
+++ b/ash/capture_mode/test_capture_mode_delegate.cc
@@ -7,12 +7,12 @@
 #include "ash/capture_mode/capture_mode_types.h"
 #include "ash/capture_mode/fake_video_source_provider.h"
 #include "ash/public/cpp/capture_mode/recording_overlay_view.h"
-#include "ash/services/recording/public/mojom/recording_service.mojom.h"
-#include "ash/services/recording/recording_service_test_api.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
 #include "base/files/file_util.h"
 #include "base/threading/thread_restrictions.h"
+#include "chromeos/ash/services/recording/public/mojom/recording_service.mojom.h"
+#include "chromeos/ash/services/recording/recording_service_test_api.h"
 
 namespace ash {
 
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 64664f1..67d57a0 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -686,6 +686,11 @@
              "EcheSWADisableStunServer",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// If enabled, allows the creation of up to 16 desks (default is 8).
+BASE_FEATURE(kEnable16Desks,
+             "Enable16Desks",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // Enables background blur for the app list, shelf, unified system tray,
 // autoclick menu, etc. Also enables the AppsGridView mask layer, slower devices
 // may have choppier app list animations while in this mode. crbug.com/765292.
@@ -1639,7 +1644,7 @@
 // secondary account.
 BASE_FEATURE(kProjectorViewerUseSecondaryAccount,
              "ProjectorViewerUseSecondaryAccount",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 // Controls whether the quick dim prototype is enabled.
 BASE_FEATURE(kQuickDim, "QuickDim", base::FEATURE_ENABLED_BY_DEFAULT);
@@ -1649,6 +1654,16 @@
              "VCBackgroundBlur",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Controls whether the vc background replace is enabled.
+BASE_FEATURE(kVCBackgroundReplace,
+             "VCBackgroundReplace",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+// Controls whether the vc portrait relighting is enabled.
+BASE_FEATURE(kVCPortraitRelighting,
+             "VCPortraitRelighting",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // Enables or disables the Quick Settings Network revamp, which updates Network
 // Quick Settings UI and related infrastructure. See https://crbug.com/1169479.
 BASE_FEATURE(kQuickSettingsNetworkRevamp,
@@ -2176,6 +2191,10 @@
   return base::FeatureList::IsEnabled(kWindowsFollowCursor);
 }
 
+bool Is16DesksEnabled() {
+  return base::FeatureList::IsEnabled(kEnable16Desks);
+}
+
 bool IsAdaptiveChargingEnabled() {
   return base::FeatureList::IsEnabled(kAdaptiveCharging);
 }
@@ -2873,8 +2892,6 @@
 }
 
 bool IsProjectorViewerUseSecondaryAccountEnabled() {
-  // TODO(b/250646696): enable this feature based on
-  // ProjectorBleedingEdgeExperience when it is ready to be tested.
   return base::FeatureList::IsEnabled(kProjectorViewerUseSecondaryAccount);
 }
 
@@ -3004,6 +3021,14 @@
   return base::FeatureList::IsEnabled(kVCBackgroundBlur);
 }
 
+bool IsVCBackgroundReplaceEnabled() {
+  return base::FeatureList::IsEnabled(kVCBackgroundReplace);
+}
+
+bool IsVCPortraitRelightingEnabled() {
+  return base::FeatureList::IsEnabled(kVCPortraitRelighting);
+}
+
 bool IsVcControlsUiEnabled() {
   return base::FeatureList::IsEnabled(kVcControlsUi);
 }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index be68720a..a5315de 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -241,6 +241,7 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kEnableOobeThemeSelection);
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kEnableSamlNotificationOnPasswordChangeSuccess);
+COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kEnable16Desks);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kEnableSavedDesks);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kEnableAllSystemWebApps);
 COMPONENT_EXPORT(ASH_CONSTANTS)
@@ -469,6 +470,8 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kQsRevamp);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kQuickDim);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kVCBackgroundBlur);
+COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kVCBackgroundReplace);
+COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kVCPortraitRelighting);
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kQuickSettingsNetworkRevamp);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kQuickUnlockFingerprint);
@@ -601,6 +604,7 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsAvatarsCloudMigrationEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool AreImprovedScreenCaptureSettingsEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool DoWindowsFollowCursor();
+COMPONENT_EXPORT(ASH_CONSTANTS) bool Is16DesksEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsAdaptiveChargingEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsAdaptiveChargingForTestingEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsAdjustSplitViewForVKEnabled();
@@ -828,6 +832,8 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsUseLoginShelfWidgetEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsUseStorkSmdsServerAddressEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsVCBackgroundBlurEnabled();
+COMPONENT_EXPORT(ASH_CONSTANTS) bool IsVCBackgroundReplaceEnabled();
+COMPONENT_EXPORT(ASH_CONSTANTS) bool IsVCPortraitRelightingEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsVcControlsUiEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsWallpaperFastRefreshEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsWallpaperFullScreenPreviewEnabled();
diff --git a/ash/public/cpp/shell_window_ids.cc b/ash/public/cpp/shell_window_ids.cc
index 64f6ef8..ea47d5a 100644
--- a/ash/public/cpp/shell_window_ids.cc
+++ b/ash/public/cpp/shell_window_ids.cc
@@ -44,23 +44,34 @@
     kShellWindowId_ShelfBubbleContainer,
 };
 
+// List of desk container IDs. Can't use desks_util since we're in ash/public
+// here.
+constexpr std::array<int, 16> kDeskContainerIds = {
+    kShellWindowId_DefaultContainerDeprecated,
+    kShellWindowId_DeskContainerB,
+    kShellWindowId_DeskContainerC,
+    kShellWindowId_DeskContainerD,
+    kShellWindowId_DeskContainerE,
+    kShellWindowId_DeskContainerF,
+    kShellWindowId_DeskContainerG,
+    kShellWindowId_DeskContainerH,
+    kShellWindowId_DeskContainerI,
+    kShellWindowId_DeskContainerJ,
+    kShellWindowId_DeskContainerK,
+    kShellWindowId_DeskContainerL,
+    kShellWindowId_DeskContainerM,
+    kShellWindowId_DeskContainerN,
+    kShellWindowId_DeskContainerO,
+    kShellWindowId_DeskContainerP,
+};
+
 }  // namespace
 
 std::vector<int> GetActivatableShellWindowIds() {
   std::vector<int> ids(kPreDesksActivatableContainersIds.begin(),
                        kPreDesksActivatableContainersIds.end());
 
-  // Add the desks containers IDs. Can't use desks_util since we're in
-  // ash/public here.
-  ids.emplace_back(kShellWindowId_DefaultContainerDeprecated);
-  ids.emplace_back(kShellWindowId_DeskContainerB);
-  ids.emplace_back(kShellWindowId_DeskContainerC);
-  ids.emplace_back(kShellWindowId_DeskContainerD);
-  ids.emplace_back(kShellWindowId_DeskContainerE);
-  ids.emplace_back(kShellWindowId_DeskContainerF);
-  ids.emplace_back(kShellWindowId_DeskContainerG);
-  ids.emplace_back(kShellWindowId_DeskContainerH);
-
+  ids.insert(ids.end(), kDeskContainerIds.begin(), kDeskContainerIds.end());
   ids.insert(ids.end(), kPostDesksActivatableContainersIds.begin(),
              kPostDesksActivatableContainersIds.end());
   return ids;
diff --git a/ash/public/cpp/shell_window_ids.h b/ash/public/cpp/shell_window_ids.h
index e7e8ba4..8d15f6d 100644
--- a/ash/public/cpp/shell_window_ids.h
+++ b/ash/public/cpp/shell_window_ids.h
@@ -78,6 +78,14 @@
   kShellWindowId_DeskContainerF,
   kShellWindowId_DeskContainerG,
   kShellWindowId_DeskContainerH,
+  kShellWindowId_DeskContainerI,
+  kShellWindowId_DeskContainerJ,
+  kShellWindowId_DeskContainerK,
+  kShellWindowId_DeskContainerL,
+  kShellWindowId_DeskContainerM,
+  kShellWindowId_DeskContainerN,
+  kShellWindowId_DeskContainerO,
+  kShellWindowId_DeskContainerP,
 
   // The container for top-level windows with the 'always-on-top' flag set.
   kShellWindowId_AlwaysOnTopContainer,
diff --git a/ash/shelf/shelf.cc b/ash/shelf/shelf.cc
index e81d3139..18df6440f 100644
--- a/ash/shelf/shelf.cc
+++ b/ash/shelf/shelf.cc
@@ -602,23 +602,19 @@
   if (!shelf_layout_manager_->is_active_session_state())
     return;
 
-  // Productivity launcher does not show or hide on scroll events by default.
   // Introduce the swipe up gesture behind a flag over certain conditions.
-  if (features::IsProductivityLauncherEnabled() &&
-      !shelf_layout_manager_->IsBubbleLauncherShowOnGestureScrollAvailable()) {
+  if (!shelf_layout_manager_->IsBubbleLauncherShowOnGestureScrollAvailable())
     return;
-  }
 
   auto* app_list_controller = Shell::Get()->app_list_controller();
   DCHECK(app_list_controller);
-  // If the App List is not visible, send Scroll events to the
-  // |shelf_layout_manager_| because these events are used to show the App
-  // List.
-  if (app_list_controller->IsVisible(shelf_layout_manager_->display_.id())) {
-    app_list_controller->ProcessScrollEvent(*event);
-  } else {
-    shelf_layout_manager_->ProcessScrollEventFromShelf(event);
-  }
+  // |shelf_layout_manager_| handles scroll events to toggle the App List. If
+  // the AppList is already showing, the event must not be handled since hiding
+  // the app list is not in scope for this action.
+  if (app_list_controller->IsVisible(shelf_layout_manager_->display_.id()))
+    return;
+
+  shelf_layout_manager_->ProcessScrollEventFromShelf(event);
   event->SetHandled();
 }
 
@@ -627,22 +623,19 @@
       !IsHorizontalAlignment())
     return;
 
-  // Productivity launcher does not show or hide on scroll events by default.
   // Introduce the swipe up gesture behind a flag over certain conditions.
-  if (features::IsProductivityLauncherEnabled() &&
-      !shelf_layout_manager_->IsBubbleLauncherShowOnGestureScrollAvailable()) {
+  if (!shelf_layout_manager_->IsBubbleLauncherShowOnGestureScrollAvailable())
     return;
-  }
 
   auto* app_list_controller = Shell::Get()->app_list_controller();
   DCHECK(app_list_controller);
-  // If the App List is not visible, send MouseWheel events to the
-  // |shelf_layout_manager_| because these events are used to show the App List.
-  if (app_list_controller->IsVisible(shelf_layout_manager_->display_.id())) {
-    app_list_controller->ProcessMouseWheelEvent(*event);
-  } else {
-    shelf_layout_manager_->ProcessMouseWheelEventFromShelf(event);
-  }
+  // |shelf_layout_manager_| handles mousewheel events to toggle the App List.
+  // If the AppList is already showing, the event must not be handled since
+  // hiding the app list is not in scope for this action.
+  if (app_list_controller->IsVisible(shelf_layout_manager_->display_.id()))
+    return;
+
+  shelf_layout_manager_->ProcessMouseWheelEventFromShelf(event);
   event->SetHandled();
 }
 
diff --git a/ash/style/color_util.cc b/ash/style/color_util.cc
index 03d7f86..aebf508 100644
--- a/ash/style/color_util.cc
+++ b/ash/style/color_util.cc
@@ -4,24 +4,73 @@
 
 #include "ash/style/color_util.h"
 
+#include "ash/constants/ash_features.h"
+#include "ash/public/cpp/wallpaper/wallpaper_types.h"
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
 #include "ash/wallpaper/wallpaper_controller_impl.h"
+#include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/color_analysis.h"
+#include "ui/gfx/color_utils.h"
 
 namespace ash {
 
+namespace {
+
 // Alpha value that is used to calculate themed color. Please see function
 // GetBackgroundThemedColor() about how the themed color is calculated.
 constexpr int kDarkBackgroundBlendAlpha = 127;   // 50%
 constexpr int kLightBackgroundBlendAlpha = 127;  // 50%
 
+// Alternate alpha values used when `kDarkLightModeKMeansColor` is active.
+constexpr int kDarkBackgroundBlendKMeansAlpha = 204;   // 80%
+constexpr int kLightBackgroundBlendKMeansAlpha = 230;  // 90%
+
 // The disabled color is always 38% opacity of the enabled color.
 constexpr float kDisabledColorOpacity = 0.38f;
 
 // Color of second tone is always 30% opacity of the color of first tone.
 constexpr float kSecondToneOpacity = 0.3f;
 
+// Get a color extracted from the user's wallpaper.
+// Returns `kInvalidWallpaperColor` on failure.
+// If `use_dark_color`, may attempt to extract a dark color from the wallpaper.
+SkColor GetUserWallpaperColor(bool use_dark_color) {
+  // May be null in unit tests.
+  if (!Shell::HasInstance())
+    return kInvalidWallpaperColor;
+
+  WallpaperControllerImpl* wallpaper_controller =
+      Shell::Get()->wallpaper_controller();
+
+  if (!wallpaper_controller)
+    return kInvalidWallpaperColor;
+
+  if (features::IsDarkLightModeKMeansColorEnabled()) {
+    // If feature is enabled, always use k mean color. Mixing with black/white
+    // will handle adapting it to dark or light mode.
+    return wallpaper_controller->GetKMeanColor();
+  }
+
+  color_utils::LumaRange luma_range = use_dark_color
+                                          ? color_utils::LumaRange::DARK
+                                          : color_utils::LumaRange::LIGHT;
+
+  return wallpaper_controller->GetProminentColor(color_utils::ColorProfile(
+      luma_range, color_utils::SaturationRange::MUTED));
+}
+
+int GetForegroundAlpha(bool use_dark_color) {
+  if (features::IsDarkLightModeKMeansColorEnabled()) {
+    return use_dark_color ? kDarkBackgroundBlendKMeansAlpha
+                          : kLightBackgroundBlendKMeansAlpha;
+  }
+  return use_dark_color ? kDarkBackgroundBlendAlpha
+                        : kLightBackgroundBlendAlpha;
+}
+
+}  // namespace
+
 // static
 ui::ColorProviderSource* ColorUtil::GetColorProviderSourceForWindow(
     const aura::Window* window) {
@@ -35,28 +84,21 @@
 // static
 SkColor ColorUtil::GetBackgroundThemedColor(SkColor default_color,
                                             bool use_dark_color) {
-  // May be null in unit tests.
-  if (!Shell::HasInstance())
+  const SkColor wallpaper_color = GetUserWallpaperColor(use_dark_color);
+  if (wallpaper_color == kInvalidWallpaperColor) {
+    DVLOG(1) << "Failed to get wallpaper color";
     return default_color;
-  WallpaperControllerImpl* wallpaper_controller =
-      Shell::Get()->wallpaper_controller();
-  if (!wallpaper_controller)
-    return default_color;
+  }
 
-  color_utils::LumaRange luma_range = use_dark_color
-                                          ? color_utils::LumaRange::DARK
-                                          : color_utils::LumaRange::LIGHT;
-  SkColor muted_color =
-      wallpaper_controller->GetProminentColor(color_utils::ColorProfile(
-          luma_range, color_utils::SaturationRange::MUTED));
-  if (muted_color == kInvalidWallpaperColor)
-    return default_color;
+  const SkColor foreground_color =
+      use_dark_color ? SK_ColorBLACK : SK_ColorWHITE;
 
+  const int foreground_alpha = GetForegroundAlpha(use_dark_color);
+
+  // Put a slightly transparent screen of white/black on top of the user's
+  // wallpaper color.
   return color_utils::GetResultingPaintColor(
-      SkColorSetA(use_dark_color ? SK_ColorBLACK : SK_ColorWHITE,
-                  use_dark_color ? kDarkBackgroundBlendAlpha
-                                 : kLightBackgroundBlendAlpha),
-      muted_color);
+      SkColorSetA(foreground_color, foreground_alpha), wallpaper_color);
 }
 
 // static
diff --git a/ash/style/color_util_unittest.cc b/ash/style/color_util_unittest.cc
new file mode 100644
index 0000000..eb2b9c0
--- /dev/null
+++ b/ash/style/color_util_unittest.cc
@@ -0,0 +1,92 @@
+// 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 "ash/style/color_util.h"
+
+#include "ash/constants/ash_features.h"
+#include "ash/public/cpp/wallpaper/wallpaper_types.h"
+#include "ash/shell.h"
+#include "ash/test/ash_test_base.h"
+#include "ash/wallpaper/wallpaper_controller_impl.h"
+#include "ash/wallpaper/wallpaper_controller_test_api.h"
+#include "ash/wallpaper/wallpaper_utils/wallpaper_calculated_colors.h"
+#include "base/test/scoped_feature_list.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/test/sk_color_eq.h"
+
+namespace ash {
+
+namespace {
+
+constexpr SkColor kTestDefaultColor = SK_ColorYELLOW;
+
+}  // namespace
+
+class ColorUtilTest : public AshTestBase {
+ public:
+  ColorUtilTest() {
+    scoped_feature_list_.InitAndEnableFeature(
+        features::kDarkLightModeKMeansColor);
+  }
+
+  ColorUtilTest(const ColorUtilTest&) = delete;
+  ColorUtilTest& operator=(const ColorUtilTest&) = delete;
+
+  void SetUp() override {
+    AshTestBase::SetUp();
+    wallpaper_controller_test_api_ =
+        std::make_unique<WallpaperControllerTestApi>(
+            Shell::Get()->wallpaper_controller());
+  }
+
+  WallpaperControllerTestApi* test_api() {
+    return wallpaper_controller_test_api_.get();
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+  std::unique_ptr<WallpaperControllerTestApi> wallpaper_controller_test_api_;
+};
+
+TEST_F(ColorUtilTest, DefaultsToDefaultColor) {
+  test_api()->SetCalculatedColors(
+      {/*prominent_colors=*/{}, /*k_mean_color=*/kInvalidWallpaperColor});
+  for (const bool use_dark_color : {true, false}) {
+    EXPECT_SKCOLOR_EQ(
+        kTestDefaultColor,
+        ColorUtil::GetBackgroundThemedColor(kTestDefaultColor, use_dark_color));
+  }
+}
+
+TEST_F(ColorUtilTest, MixesWithWhiteInLightMode) {
+  // Tuple of k_mean_color, expected output color after masking with white.
+  std::vector<std::tuple<SkColor, SkColor>> cases = {
+      {SK_ColorRED, SkColorSetARGB(0xFF, 0xFF, 0xE6, 0xE6)},
+      {SK_ColorGREEN, SkColorSetARGB(0xFF, 0xE6, 0xFF, 0xE6)},
+      {SK_ColorMAGENTA, SkColorSetARGB(0xFF, 0xFF, 0xE6, 0xFF)},
+  };
+  for (const auto& [k_mean_color, expected_color] : cases) {
+    test_api()->SetCalculatedColors({{}, k_mean_color});
+    SkColor result_color =
+        ColorUtil::GetBackgroundThemedColor(kTestDefaultColor, false);
+    EXPECT_SKCOLOR_EQ(expected_color, result_color);
+  }
+}
+
+TEST_F(ColorUtilTest, MixesWithBlackInDarkMode) {
+  // Tuple of k_mean_color, expected output color after masking with black.
+  std::vector<std::tuple<SkColor, SkColor>> cases = {
+      {SK_ColorRED, SkColorSetARGB(0xFF, 0x33, 0x00, 0x00)},
+      {SK_ColorGREEN, SkColorSetARGB(0xFF, 0x00, 0x33, 0x00)},
+      {SK_ColorMAGENTA, SkColorSetARGB(0xFF, 0x33, 0x00, 0x33)},
+  };
+  for (const auto& [k_mean_color, expected_color] : cases) {
+    test_api()->SetCalculatedColors({{}, k_mean_color});
+    SkColor result_color =
+        ColorUtil::GetBackgroundThemedColor(kTestDefaultColor, true);
+    EXPECT_SKCOLOR_EQ(expected_color, result_color);
+  }
+}
+
+}  // namespace ash
diff --git a/ash/system/holding_space/holding_space_tray_bubble.cc b/ash/system/holding_space/holding_space_tray_bubble.cc
index 3165ddf..1fec34cf 100644
--- a/ash/system/holding_space/holding_space_tray_bubble.cc
+++ b/ash/system/holding_space/holding_space_tray_bubble.cc
@@ -4,6 +4,7 @@
 
 #include "ash/system/holding_space/holding_space_tray_bubble.h"
 
+#include <map>
 #include <vector>
 
 #include "ash/bubble/bubble_utils.h"
@@ -26,6 +27,7 @@
 #include "ash/wm/work_area_insets.h"
 #include "base/bind.h"
 #include "base/containers/adapters.h"
+#include "base/scoped_observation.h"
 #include "ui/aura/env.h"
 #include "ui/aura/window.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -38,6 +40,7 @@
 #include "ui/views/animation/animation_delegate_views.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/proposed_layout.h"
+#include "ui/views/view_observer.h"
 
 namespace ash {
 
@@ -195,6 +198,38 @@
   int max_height_ = 0;
 };
 
+// ScopedViewBoundsChangedObserver ---------------------------------------------
+
+// A class which observes a view until destruction, forwarding bounds changed
+// events to a constructor-provided callback.
+class ScopedViewBoundsChangedObserver : public views::ViewObserver {
+ public:
+  ScopedViewBoundsChangedObserver(
+      views::View* view,
+      base::RepeatingClosure on_view_bounds_changed_callback)
+      : on_view_bounds_changed_callback_(on_view_bounds_changed_callback) {
+    DCHECK(on_view_bounds_changed_callback);
+    observation_.Observe(view);
+  }
+
+  ScopedViewBoundsChangedObserver(const ScopedViewBoundsChangedObserver&) =
+      delete;
+  ScopedViewBoundsChangedObserver& operator=(
+      const ScopedViewBoundsChangedObserver&) = delete;
+  ~ScopedViewBoundsChangedObserver() override = default;
+
+ private:
+  // views::ViewObserver:
+  void OnViewBoundsChanged(views::View* view) override {
+    on_view_bounds_changed_callback_.Run();
+  }
+
+  void OnViewIsDeleting(views::View* view) override { observation_.Reset(); }
+
+  base::RepeatingClosure on_view_bounds_changed_callback_;
+  base::ScopedObservation<views::View, views::ViewObserver> observation_{this};
+};
+
 }  // namespace
 
 // HoldingSpaceTrayBubble::ChildBubbleContainer --------------------------------
@@ -224,6 +259,42 @@
     return current_layout_.host_size.height();
   }
 
+  void ViewHierarchyChanged(
+      const views::ViewHierarchyChangedDetails& details) override {
+    views::View::ViewHierarchyChanged(details);
+
+    // When UI refresh is enabled we need to observe child bubbles for bounds
+    // changes to ensure that separators are repainted appropriately. This is
+    // not relevant when UI refresh is disabled.
+    if (!features::IsHoldingSpaceRefreshEnabled())
+      return;
+
+    // Only handle addition/removal of child bubbles.
+    if (details.parent != this)
+      return;
+
+    // When child bubbles are removed they no longer need to be observed. This
+    // should only happen during destruction of the holding space tray bubble,
+    // but we'll schedule a paint anyway just to be extra cautious.
+    if (!details.is_add) {
+      view_bounds_changed_observers_by_view_.erase(details.child);
+      SchedulePaint();
+      return;
+    }
+
+    // When child bubbles are added they need to be observed so that we can
+    // ensure bounds changes always result in repainting of separators. Unless
+    // we do so explicitly, separators would only otherwise be repainted when
+    // the bounds of `this` view also change. This is not the case when holding
+    // space has reached its maximum height.
+    view_bounds_changed_observers_by_view_.emplace(
+        std::piecewise_construct, /*view=*/std::forward_as_tuple(details.child),
+        std::forward_as_tuple(
+            /*view=*/details.child,
+            /*on_view_bounds_changed_callback=*/base::BindRepeating(
+                &ChildBubbleContainer::SchedulePaint, base::Unretained(this))));
+  }
+
   void ChildPreferredSizeChanged(views::View* child) override {
     PreferredSizeChanged();
   }
@@ -338,6 +409,12 @@
 
   std::unique_ptr<gfx::SlideAnimation> layout_animation_;
   absl::optional<ui::ThroughputTracker> layout_animation_throughput_tracker_;
+
+  // Mapping of view bounds changed observers to the views which they observe.
+  // This is used when UI refresh is enabled to ensure that separators are
+  // repainted when child bubble bounds change.
+  std::map<const views::View*, ScopedViewBoundsChangedObserver>
+      view_bounds_changed_observers_by_view_;
 };
 
 // HoldingSpaceTrayBubble ------------------------------------------------------
diff --git a/ash/wallpaper/wallpaper_controller_test_api.cc b/ash/wallpaper/wallpaper_controller_test_api.cc
index 97e16574..e05928d8 100644
--- a/ash/wallpaper/wallpaper_controller_test_api.cc
+++ b/ash/wallpaper/wallpaper_controller_test_api.cc
@@ -3,7 +3,12 @@
 // found in the LICENSE file.
 
 #include "ash/wallpaper/wallpaper_controller_test_api.h"
+
+#include <memory>
+
 #include "ash/wallpaper/wallpaper_controller_impl.h"
+#include "ash/wallpaper/wallpaper_utils/wallpaper_calculated_colors.h"
+#include "ash/wallpaper/wallpaper_utils/wallpaper_color_calculator.h"
 #include "base/bind.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/color_utils.h"
@@ -57,4 +62,13 @@
     controller_->CancelPreviewWallpaper();
 }
 
+void WallpaperControllerTestApi::SetCalculatedColors(
+    const WallpaperCalculatedColors& calculated_colors) {
+  if (controller_->color_calculator_) {
+    controller_->color_calculator_->RemoveObserver(controller_);
+    controller_->color_calculator_.reset();
+  }
+  controller_->SetCalculatedColors(calculated_colors);
+}
+
 }  // namespace ash
diff --git a/ash/wallpaper/wallpaper_controller_test_api.h b/ash/wallpaper/wallpaper_controller_test_api.h
index e8aed19..f870ffc3 100644
--- a/ash/wallpaper/wallpaper_controller_test_api.h
+++ b/ash/wallpaper/wallpaper_controller_test_api.h
@@ -6,7 +6,7 @@
 #define ASH_WALLPAPER_WALLPAPER_CONTROLLER_TEST_API_H_
 
 #include "ash/ash_export.h"
-#include "third_party/skia/include/core/SkColor.h"
+#include "ash/wallpaper/wallpaper_utils/wallpaper_calculated_colors.h"
 
 namespace ash {
 
@@ -30,6 +30,11 @@
   // set as the actual user wallpaper.
   void EndWallpaperPreview(bool confirm_preview_wallpaper);
 
+  // Force a specific set of `calculated_colors` to be set to
+  // WallpaperController. Cancels any ongoing requests to calculate wallpaper
+  // colors.
+  void SetCalculatedColors(const WallpaperCalculatedColors& calculated_colors);
+
  private:
   WallpaperControllerImpl* controller_;
 };
diff --git a/ash/wm/desks/autotest_desks_api_unittests.cc b/ash/wm/desks/autotest_desks_api_unittests.cc
index af8090df..2fd72e2 100644
--- a/ash/wm/desks/autotest_desks_api_unittests.cc
+++ b/ash/wm/desks/autotest_desks_api_unittests.cc
@@ -69,7 +69,7 @@
   auto* controller = DesksController::Get();
   while (controller->CanCreateDesks())
     EXPECT_TRUE(test_api.CreateNewDesk());
-  EXPECT_EQ(desks_util::kMaxNumberOfDesks, controller->desks().size());
+  EXPECT_EQ(desks_util::GetMaxNumberOfDesks(), controller->desks().size());
   constexpr int kIndices[] = {1, 2, 3, 0};
   for (const int index : kIndices) {
     base::RunLoop run_loop;
@@ -83,7 +83,7 @@
   AutotestDesksApi test_api;
   EXPECT_FALSE(test_api.RemoveActiveDesk(base::DoNothing()));
 
-  const size_t max_number_of_desks = desks_util::kMaxNumberOfDesks;
+  const size_t max_number_of_desks = desks_util::GetMaxNumberOfDesks();
   auto* controller = DesksController::Get();
   while (controller->CanCreateDesks())
     EXPECT_TRUE(test_api.CreateNewDesk());
@@ -114,7 +114,7 @@
        DISABLED_ActivateAdjacentDesksToTargetIndex) {
   // Create all desks possible.
   AutotestDesksApi test_api;
-  const int max_number_of_desks = desks_util::kMaxNumberOfDesks;
+  const int max_number_of_desks = desks_util::GetMaxNumberOfDesks();
   auto* controller = DesksController::Get();
   while (controller->CanCreateDesks())
     EXPECT_TRUE(test_api.CreateNewDesk());
@@ -127,7 +127,7 @@
   // Activating already active desk does nothing.
   EXPECT_FALSE(
       test_api.ActivateAdjacentDesksToTargetIndex(0, base::DoNothing()));
-  EXPECT_EQ(desks_util::kMaxNumberOfDesks, controller->desks().size());
+  EXPECT_EQ(desks_util::GetMaxNumberOfDesks(), controller->desks().size());
 
   // Replacing needs to be done while a current animation is underway, otherwise
   // it will have no effect.
diff --git a/ash/wm/desks/desks_bar_view.cc b/ash/wm/desks/desks_bar_view.cc
index a4a8286..096f2db7 100644
--- a/ash/wm/desks/desks_bar_view.cc
+++ b/ash/wm/desks/desks_bar_view.cc
@@ -834,6 +834,9 @@
   const bool is_expanding_bar_view = zero_state_new_desk_button_->GetVisible();
   UpdateNewMiniViews(/*initializing_bar_view=*/false, is_expanding_bar_view);
   MaybeUpdateCombineDesksTooltips();
+
+  if (!DesksController::Get()->CanCreateDesks())
+    expanded_state_new_desk_button_->SetButtonState(/*enabled=*/false);
 }
 
 void DesksBarView::OnDeskRemoved(const Desk* desk) {
@@ -1009,8 +1012,6 @@
   if (!controller->CanCreateDesks())
     return;
   controller->NewDesk(desks_creation_removal_source);
-  if (!controller->CanCreateDesks())
-    expanded_state_new_desk_button_->SetButtonState(/*enabled=*/false);
   NudgeDeskName(mini_views_.size() - 1);
 }
 
diff --git a/ash/wm/desks/desks_controller.cc b/ash/wm/desks/desks_controller.cc
index 7d6026c..71a26a0a 100644
--- a/ash/wm/desks/desks_controller.cc
+++ b/ash/wm/desks/desks_controller.cc
@@ -104,23 +104,9 @@
     "Ash.Desks.NumberOfWindowsClosed.SaveRecall";
 constexpr char kNumberOfWindowsClosedByApi[] =
     "Ash.Desks.NumberOfWindowsClosed.Api";
-
-constexpr char kNumberOfWindowsOnDesk_1_HistogramName[] =
-    "Ash.Desks.NumberOfWindowsOnDesk_1";
-constexpr char kNumberOfWindowsOnDesk_2_HistogramName[] =
-    "Ash.Desks.NumberOfWindowsOnDesk_2";
-constexpr char kNumberOfWindowsOnDesk_3_HistogramName[] =
-    "Ash.Desks.NumberOfWindowsOnDesk_3";
-constexpr char kNumberOfWindowsOnDesk_4_HistogramName[] =
-    "Ash.Desks.NumberOfWindowsOnDesk_4";
-constexpr char kNumberOfWindowsOnDesk_5_HistogramName[] =
-    "Ash.Desks.NumberOfWindowsOnDesk_5";
-constexpr char kNumberOfWindowsOnDesk_6_HistogramName[] =
-    "Ash.Desks.NumberOfWindowsOnDesk_6";
-constexpr char kNumberOfWindowsOnDesk_7_HistogramName[] =
-    "Ash.Desks.NumberOfWindowsOnDesk_7";
-constexpr char kNumberOfWindowsOnDesk_8_HistogramName[] =
-    "Ash.Desks.NumberOfWindowsOnDesk_8";
+// Used for histograms from "Ash.Desks.NumberOfWindowsOnDesk_1" up to 16.
+constexpr char kNumberOfWindowsOnDeskHistogramPrefix[] =
+    "Ash.Desks.NumberOfWindowsOnDesk_";
 
 constexpr char kNumberOfDeskTraversalsHistogramName[] =
     "Ash.Desks.NumberOfDeskTraversals";
@@ -132,10 +118,23 @@
 constexpr base::TimeDelta kDeskTraversalsTimeout = base::Seconds(5);
 
 constexpr int kDeskDefaultNameIds[] = {
-    IDS_ASH_DESKS_DESK_1_MINI_VIEW_TITLE, IDS_ASH_DESKS_DESK_2_MINI_VIEW_TITLE,
-    IDS_ASH_DESKS_DESK_3_MINI_VIEW_TITLE, IDS_ASH_DESKS_DESK_4_MINI_VIEW_TITLE,
-    IDS_ASH_DESKS_DESK_5_MINI_VIEW_TITLE, IDS_ASH_DESKS_DESK_6_MINI_VIEW_TITLE,
-    IDS_ASH_DESKS_DESK_7_MINI_VIEW_TITLE, IDS_ASH_DESKS_DESK_8_MINI_VIEW_TITLE};
+    IDS_ASH_DESKS_DESK_1_MINI_VIEW_TITLE,
+    IDS_ASH_DESKS_DESK_2_MINI_VIEW_TITLE,
+    IDS_ASH_DESKS_DESK_3_MINI_VIEW_TITLE,
+    IDS_ASH_DESKS_DESK_4_MINI_VIEW_TITLE,
+    IDS_ASH_DESKS_DESK_5_MINI_VIEW_TITLE,
+    IDS_ASH_DESKS_DESK_6_MINI_VIEW_TITLE,
+    IDS_ASH_DESKS_DESK_7_MINI_VIEW_TITLE,
+    IDS_ASH_DESKS_DESK_8_MINI_VIEW_TITLE,
+    IDS_ASH_DESKS_DESK_9_MINI_VIEW_TITLE,
+    IDS_ASH_DESKS_DESK_10_MINI_VIEW_TITLE,
+    IDS_ASH_DESKS_DESK_11_MINI_VIEW_TITLE,
+    IDS_ASH_DESKS_DESK_12_MINI_VIEW_TITLE,
+    IDS_ASH_DESKS_DESK_13_MINI_VIEW_TITLE,
+    IDS_ASH_DESKS_DESK_14_MINI_VIEW_TITLE,
+    IDS_ASH_DESKS_DESK_15_MINI_VIEW_TITLE,
+    IDS_ASH_DESKS_DESK_16_MINI_VIEW_TITLE,
+};
 
 // Appends the given |windows| to the end of the currently active overview mode
 // session such that the most-recently used window is added first. If
@@ -419,7 +418,7 @@
 
 // static
 std::u16string DesksController::GetDeskDefaultName(size_t desk_index) {
-  DCHECK_LT(desk_index, desks_util::kMaxNumberOfDesks);
+  DCHECK_LT(desk_index, desks_util::GetMaxNumberOfDesks());
   return l10n_util::GetStringUTF16(kDeskDefaultNameIds[desk_index]);
 }
 
@@ -493,7 +492,7 @@
 }
 
 bool DesksController::CanCreateDesks() const {
-  return desks_.size() < desks_util::kMaxNumberOfDesks;
+  return desks_.size() < desks_util::GetMaxNumberOfDesks();
 }
 
 Desk* DesksController::GetNextDesk(bool use_target_active_desk) const {
@@ -1699,7 +1698,7 @@
   desks_restore_util::UpdatePrimaryUserDeskNamesPrefs();
   desks_restore_util::UpdatePrimaryUserDeskMetricsPrefs();
 
-  DCHECK_LE(available_container_ids_.size(), desks_util::kMaxNumberOfDesks);
+  DCHECK_LE(available_container_ids_.size(), desks_util::GetMaxNumberOfDesks());
 
   if (close_type == DeskCloseType::kCloseAllWindowsAndWait) {
     ShowDeskRemovalUndoToast(
@@ -1961,60 +1960,19 @@
 }
 
 void DesksController::ReportNumberOfWindowsPerDeskHistogram() const {
+  DCHECK_LE(desks_.size(), desks_util::kDesksUpperLimit);
   for (size_t i = 0; i < desks_.size(); ++i) {
     const size_t windows_count = desks_[i]->windows().size();
-    switch (i) {
-      case 0:
-        UMA_HISTOGRAM_COUNTS_100(kNumberOfWindowsOnDesk_1_HistogramName,
-                                 windows_count);
-        break;
-
-      case 1:
-        UMA_HISTOGRAM_COUNTS_100(kNumberOfWindowsOnDesk_2_HistogramName,
-                                 windows_count);
-        break;
-
-      case 2:
-        UMA_HISTOGRAM_COUNTS_100(kNumberOfWindowsOnDesk_3_HistogramName,
-                                 windows_count);
-        break;
-
-      case 3:
-        UMA_HISTOGRAM_COUNTS_100(kNumberOfWindowsOnDesk_4_HistogramName,
-                                 windows_count);
-        break;
-
-      case 4:
-        UMA_HISTOGRAM_COUNTS_100(kNumberOfWindowsOnDesk_5_HistogramName,
-                                 windows_count);
-        break;
-
-      case 5:
-        UMA_HISTOGRAM_COUNTS_100(kNumberOfWindowsOnDesk_6_HistogramName,
-                                 windows_count);
-        break;
-
-      case 6:
-        UMA_HISTOGRAM_COUNTS_100(kNumberOfWindowsOnDesk_7_HistogramName,
-                                 windows_count);
-        break;
-
-      case 7:
-        UMA_HISTOGRAM_COUNTS_100(kNumberOfWindowsOnDesk_8_HistogramName,
-                                 windows_count);
-        break;
-
-      default:
-        NOTREACHED();
-        break;
-    }
+    base::UmaHistogramCounts100(
+        kNumberOfWindowsOnDeskHistogramPrefix + base::NumberToString(i + 1),
+        windows_count);
   }
 }
 
 void DesksController::ReportDesksCountHistogram() const {
-  DCHECK_LE(desks_.size(), desks_util::kMaxNumberOfDesks);
+  DCHECK_LE(desks_.size(), desks_util::kDesksUpperLimit);
   UMA_HISTOGRAM_EXACT_LINEAR(kDesksCountHistogramName, desks_.size(),
-                             desks_util::kMaxNumberOfDesks);
+                             desks_util::kDesksUpperLimit + 1);
 }
 
 void DesksController::RecordAndResetNumberOfWeeklyActiveDesks() {
diff --git a/ash/wm/desks/desks_restore_util.cc b/ash/wm/desks/desks_restore_util.cc
index 75d9765..49a0963 100644
--- a/ash/wm/desks/desks_restore_util.cc
+++ b/ash/wm/desks/desks_restore_util.cc
@@ -80,9 +80,7 @@
 // DesksController.
 bool IsValidDeskIndex(int desk_index) {
   return desk_index >= 0 &&
-         desk_index <
-             static_cast<int>(DesksController::Get()->desks().size()) &&
-         desk_index < int{desks_util::kMaxNumberOfDesks};
+         desk_index < static_cast<int>(DesksController::Get()->desks().size());
 }
 
 base::Time GetTime(int year, int month, int day_of_month, int day_of_week) {
@@ -151,13 +149,16 @@
       primary_user_prefs->GetList(prefs::kDesksMetricsList);
 
   // First create the same number of desks.
-  const size_t restore_size = desks_names_list.size();
+  size_t restore_size = desks_names_list.size();
 
-  // If we don't have any restore data, or the list is corrupt for some reason,
-  // abort.
-  if (!restore_size || restore_size > desks_util::kMaxNumberOfDesks)
+  // If we don't have any restore data, abort.
+  if (restore_size == 0)
     return;
 
+  // If we have more restore data than the *current* max, clamp it. This can
+  // happen if the restore data was created when more desks were permitted.
+  restore_size = std::min(restore_size, desks_util::GetMaxNumberOfDesks());
+
   auto* desks_controller = DesksController::Get();
   while (desks_controller->desks().size() < restore_size)
     desks_controller->NewDesk(DesksCreationRemovalSource::kDesksRestore);
diff --git a/ash/wm/desks/desks_unittests.cc b/ash/wm/desks/desks_unittests.cc
index a6a30f82..6a47920 100644
--- a/ash/wm/desks/desks_unittests.cc
+++ b/ash/wm/desks/desks_unittests.cc
@@ -132,6 +132,8 @@
 
 namespace {
 
+using ::testing::ValuesIn;
+
 void NewDesk() {
   // Create a desk through keyboard. Do not use |kButton| to avoid empty name.
   DesksController::Get()->NewDesk(DesksCreationRemovalSource::kKeyboard);
@@ -381,10 +383,14 @@
   }
 };
 
-// Defines a test fixture to test Virtual Desks behavior, parameterized to run
-// some window drag tests with both touch gestures and with mouse events.
+struct DesksTestParams {
+  bool use_touch_gestures = false;
+  bool use_16_desks = false;
+};
+
+// Defines a parameterized test fixture to test Virtual Desks behavior.
 class DesksTest : public AshTestBase,
-                  public ::testing::WithParamInterface<bool> {
+                  public ::testing::WithParamInterface<DesksTestParams> {
  public:
   DesksTest() = default;
   explicit DesksTest(base::test::TaskEnvironment::TimeSource time)
@@ -396,16 +402,27 @@
   ~DesksTest() override = default;
 
   void SetUp() override {
+    scoped_feature_list_.InitWithFeatureState(features::kEnable16Desks,
+                                              GetParam().use_16_desks);
+
     AshTestBase::SetUp();
     SetVirtualKeyboardEnabled(true);
   }
 
+  void TearDown() override {
+    AshTestBase::TearDown();
+    scoped_feature_list_.Reset();
+  }
+
   void SendKey(ui::KeyboardCode key_code, int flags = ui::EF_NONE) {
     PressAndReleaseKey(key_code, flags);
   }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
-TEST_F(DesksTest, DesksCreationAndRemoval) {
+TEST_P(DesksTest, DesksCreationAndRemoval) {
   TestObserver observer;
   auto* controller = DesksController::Get();
   controller->AddObserver(&observer);
@@ -421,8 +438,8 @@
 
   // Expect we've reached the max number of desks, and we've been notified only
   // with the newly created desks.
-  EXPECT_EQ(desks_util::kMaxNumberOfDesks, controller->desks().size());
-  EXPECT_EQ(desks_util::kMaxNumberOfDesks - 1, observer.desks().size());
+  EXPECT_EQ(desks_util::GetMaxNumberOfDesks(), controller->desks().size());
+  EXPECT_EQ(desks_util::GetMaxNumberOfDesks() - 1, observer.desks().size());
   EXPECT_TRUE(controller->CanRemoveDesks());
 
   // Remove all desks until no longer possible, and expect that there's always
@@ -444,7 +461,7 @@
 // moved to an adjacent desk, and its order in the MRU tracker is updated. But
 // the MRU tracker was not tracking it to begin with, so this case has to be
 // handled.
-TEST_F(DesksTest, DeskRemovalWithPausedMruTracker) {
+TEST_P(DesksTest, DeskRemovalWithPausedMruTracker) {
   NewDesk();
   auto* controller = DesksController::Get();
   EXPECT_EQ(2u, controller->desks().size());
@@ -466,7 +483,7 @@
 }
 
 // Verifies that desk's name change notifies |DesksController::Observer|.
-TEST_F(DesksTest, OnDeskNameChanged) {
+TEST_P(DesksTest, OnDeskNameChanged) {
   TestObserver observer;
   auto* controller = DesksController::Get();
   controller->AddObserver(&observer);
@@ -483,7 +500,7 @@
   controller->RemoveObserver(&observer);
 }
 
-TEST_F(DesksTest, DesksTextfieldAddTooltipText) {
+TEST_P(DesksTest, DesksTextfieldAddTooltipText) {
   NewDesk();
 
   auto* controller = DesksController::Get();
@@ -513,7 +530,7 @@
   EXPECT_EQ(desk_name2, desk_name_view2->GetTooltipText(gfx::Point()));
 }
 
-TEST_F(DesksTest, DesksBarViewDeskCreation) {
+TEST_P(DesksTest, DesksBarViewDeskCreation) {
   auto* controller = DesksController::Get();
 
   auto* overview_controller = Shell::Get()->overview_controller();
@@ -537,13 +554,18 @@
   auto* new_desk_button =
       desks_bar_view->expanded_state_new_desk_button()->inner_button();
   EXPECT_TRUE(new_desk_button->GetEnabled());
+
+  auto* scroll_right_button = DesksTestApi::GetDesksBarRightScrollButton();
+
   // Click many times on the expanded new desk button and expect only the max
   // number of desks will be created, and the button is no longer enabled.
-  for (size_t i = 0; i < desks_util::kMaxNumberOfDesks + 2; ++i)
+  for (size_t i = 0; i < desks_util::GetMaxNumberOfDesks() + 2; ++i) {
     ClickOnView(new_desk_button, event_generator);
+    ClickOnView(scroll_right_button, event_generator);
+  }
 
   EXPECT_TRUE(overview_grid->IsDesksBarViewActive());
-  EXPECT_EQ(desks_util::kMaxNumberOfDesks, controller->desks().size());
+  EXPECT_EQ(desks_util::GetMaxNumberOfDesks(), controller->desks().size());
   EXPECT_EQ(controller->desks().size(), desks_bar_view->mini_views().size());
   EXPECT_FALSE(controller->CanCreateDesks());
   EXPECT_TRUE(controller->CanRemoveDesks());
@@ -552,7 +574,7 @@
 
   // Hover over one of the mini_views, and expect that the desk action interface
   // becomes visible.
-  const auto* mini_view = desks_bar_view->mini_views().front();
+  const auto* mini_view = desks_bar_view->mini_views().back();
   EXPECT_FALSE(GetDeskActionVisibilityForMiniView(mini_view));
   const gfx::Point mini_view_center =
       mini_view->GetBoundsInScreen().CenterPoint();
@@ -563,7 +585,7 @@
   CloseDeskFromMiniView(mini_view, event_generator);
 
   // The new desk button is now enabled again.
-  EXPECT_EQ(desks_util::kMaxNumberOfDesks - 1, controller->desks().size());
+  EXPECT_EQ(desks_util::GetMaxNumberOfDesks() - 1, controller->desks().size());
   EXPECT_EQ(controller->desks().size(), desks_bar_view->mini_views().size());
   EXPECT_TRUE(controller->CanCreateDesks());
   EXPECT_TRUE(new_desk_button->GetEnabled());
@@ -591,7 +613,7 @@
                   ->GetEnabled());
 }
 
-TEST_F(DesksTest, RemoveDeskWithEmptyName) {
+TEST_P(DesksTest, RemoveDeskWithEmptyName) {
   auto* controller = DesksController::Get();
 
   EnterOverview();
@@ -615,7 +637,7 @@
 
 // Tests that removing a non-active desk updates the window workspaces for
 // desks restore correctly.
-TEST_F(DesksTest, RemovingNonActiveDeskUpdatesWindowWorkspaces) {
+TEST_P(DesksTest, RemovingNonActiveDeskUpdatesWindowWorkspaces) {
   auto* controller = DesksController::Get();
 
   // Create two new desks.
@@ -649,7 +671,7 @@
 
 // Tests that removing an active desk updates the window workspaces for desks
 // restore correctly.
-TEST_F(DesksTest, RemovingActiveDeskUpdatesWindowWorkspaces) {
+TEST_P(DesksTest, RemovingActiveDeskUpdatesWindowWorkspaces) {
   auto* controller = DesksController::Get();
 
   // Create three new desks.
@@ -689,7 +711,7 @@
 
 // Test that gesture taps do not reset the button state to normal when the
 // button is disabled. https://crbug.com/1084241.
-TEST_F(DesksTest, GestureTapOnNewDeskButton) {
+TEST_P(DesksTest, GestureTapOnNewDeskButton) {
   EnterOverview();
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
 
@@ -705,16 +727,20 @@
       desks_bar_view->expanded_state_new_desk_button()->inner_button();
   EXPECT_TRUE(new_desk_button->GetEnabled());
 
+  auto* scroll_right_button = DesksTestApi::GetDesksBarRightScrollButton();
+
   // Gesture tap multiple times on the new desk button until it's disabled,
   // and verify the button state.
-  for (size_t i = 0; i < desks_util::kMaxNumberOfDesks + 2; ++i)
+  for (size_t i = 0; i < desks_util::GetMaxNumberOfDesks() + 2; ++i) {
     GestureTapOnView(new_desk_button, event_generator);
+    GestureTapOnView(scroll_right_button, event_generator);
+  }
 
   EXPECT_FALSE(new_desk_button->GetEnabled());
   EXPECT_EQ(views::Button::STATE_DISABLED, new_desk_button->GetState());
 }
 
-TEST_F(DesksTest, DeskActivation) {
+TEST_P(DesksTest, DeskActivation) {
   auto* controller = DesksController::Get();
   ASSERT_EQ(1u, controller->desks().size());
   const Desk* desk_1 = controller->desks()[0].get();
@@ -774,7 +800,7 @@
   EXPECT_FALSE(desk_4->GetDeskContainerForRoot(root)->IsVisible());
 }
 
-TEST_F(DesksTest, TestWindowPositioningPaused) {
+TEST_P(DesksTest, TestWindowPositioningPaused) {
   auto* controller = DesksController::Get();
   NewDesk();
 
@@ -808,7 +834,7 @@
 
 // This test makes sure we have coverage for that desk switch animation when run
 // with multiple displays.
-TEST_F(DesksTest, DeskActivationDualDisplay) {
+TEST_P(DesksTest, DeskActivationDualDisplay) {
   UpdateDisplay("700x600,400x500");
 
   auto* controller = DesksController::Get();
@@ -846,7 +872,7 @@
   EXPECT_FALSE(desk_4->GetDeskContainerForRoot(roots[1])->IsVisible());
 }
 
-TEST_F(DesksTest, TransientWindows) {
+TEST_P(DesksTest, TransientWindows) {
   auto* controller = DesksController::Get();
   ASSERT_EQ(1u, controller->desks().size());
   const Desk* desk_1 = controller->desks()[0].get();
@@ -900,7 +926,7 @@
   EXPECT_EQ(win2.get(), desk_2_container->children()[2]);
 }
 
-TEST_F(DesksTest, WindowStackingAfterWindowMoveToAnotherDesk) {
+TEST_P(DesksTest, WindowStackingAfterWindowMoveToAnotherDesk) {
   auto* controller = DesksController::Get();
   auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
 
@@ -943,7 +969,7 @@
   EXPECT_TRUE(IsStackedBelow(win0.get(), win3.get()));
 }
 
-TEST_F(DesksTest, TransientModalChildren) {
+TEST_P(DesksTest, TransientModalChildren) {
   auto* controller = DesksController::Get();
   NewDesk();
   NewDesk();
@@ -995,7 +1021,7 @@
   EXPECT_EQ(win1.get(), ::wm::GetModalTransient(win0.get()));
 }
 
-TEST_F(DesksTest, WindowActivation) {
+TEST_P(DesksTest, WindowActivation) {
   // Create three windows.
   auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
   auto win1 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
@@ -1088,7 +1114,7 @@
   EXPECT_TRUE(wm::CanActivateWindow(win4.get()));
 }
 
-TEST_F(DesksTest, ActivateDeskFromOverview) {
+TEST_P(DesksTest, ActivateDeskFromOverview) {
   auto* controller = DesksController::Get();
   auto* overview_controller = Shell::Get()->overview_controller();
   auto* event_generator = GetEventGenerator();
@@ -1188,7 +1214,7 @@
 
 // This test makes sure we have coverage for that desk switch animation when run
 // with multiple displays while overview mode is active.
-TEST_F(DesksTest, ActivateDeskFromOverviewDualDisplay) {
+TEST_P(DesksTest, ActivateDeskFromOverviewDualDisplay) {
   UpdateDisplay("700x600,400x500");
 
   auto* controller = DesksController::Get();
@@ -1229,7 +1255,7 @@
   EXPECT_FALSE(overview_controller->InOverviewSession());
 }
 
-TEST_F(DesksTest, RemoveInactiveDeskFromOverview) {
+TEST_P(DesksTest, RemoveInactiveDeskFromOverview) {
   auto* controller = DesksController::Get();
 
   // Create three desks other than the default initial desk.
@@ -1330,7 +1356,7 @@
                 ->children());
 }
 
-TEST_F(DesksTest, RemoveActiveDeskFromOverview) {
+TEST_P(DesksTest, RemoveActiveDeskFromOverview) {
   auto* controller = DesksController::Get();
 
   // Create one desk other than the default initial desk.
@@ -1429,7 +1455,7 @@
   desk_1->RemoveObserver(&desk_1_observer);
 }
 
-TEST_F(DesksTest, ActivateActiveDeskFromOverview) {
+TEST_P(DesksTest, ActivateActiveDeskFromOverview) {
   auto* controller = DesksController::Get();
 
   // Create one more desk other than the default initial desk, so the desks bar
@@ -1453,7 +1479,7 @@
   EXPECT_EQ(desk_1, controller->active_desk());
 }
 
-TEST_F(DesksTest, MinimizedWindow) {
+TEST_P(DesksTest, MinimizedWindow) {
   auto* controller = DesksController::Get();
   NewDesk();
   ASSERT_EQ(2u, controller->desks().size());
@@ -1491,7 +1517,7 @@
 
 // Tests that the app list stays open when switching desks. Regression test for
 // http://crbug.com/1138982.
-TEST_F(DesksTest, AppListStaysOpenInClamshell) {
+TEST_P(DesksTest, AppListStaysOpenInClamshell) {
   auto* controller = DesksController::Get();
   NewDesk();
   ASSERT_EQ(2u, controller->desks().size());
@@ -1513,7 +1539,7 @@
 
 // Tests that the app list correctly loses focus in tablet mode when switching
 // desks. Regression test for https://crbug.com/1206030.
-TEST_F(DesksTest, AppListActivationInTablet) {
+TEST_P(DesksTest, AppListActivationInTablet) {
   auto* controller = DesksController::Get();
   NewDesk();
   ASSERT_EQ(2u, controller->desks().size());
@@ -1575,8 +1601,7 @@
   auto* event_generator = GetEventGenerator();
   DragItemToPoint(overview_item,
                   desk_1_mini_view->GetBoundsInScreen().CenterPoint(),
-                  event_generator,
-                  /*by_touch_gestures=*/GetParam());
+                  event_generator, GetParam().use_touch_gestures);
   EXPECT_TRUE(overview_controller->InOverviewSession());
   EXPECT_EQ(2u, overview_grid->size());
   EXPECT_EQ(target_bounds_before_drag, overview_item->target_bounds());
@@ -1588,8 +1613,7 @@
   EXPECT_EQ(desk_2, desk_2_mini_view->desk());
   DragItemToPoint(overview_item,
                   desk_2_mini_view->GetBoundsInScreen().CenterPoint(),
-                  event_generator,
-                  /*by_touch_gestures=*/GetParam());
+                  event_generator, GetParam().use_touch_gestures);
   EXPECT_TRUE(overview_controller->InOverviewSession());
   EXPECT_EQ(1u, overview_grid->size());
   EXPECT_FALSE(DoesActiveDeskContainWindow(win1.get()));
@@ -1608,7 +1632,7 @@
   ASSERT_TRUE(overview_item);
   const auto window_center =
       gfx::ToFlooredPoint(overview_item->target_bounds().CenterPoint());
-  if (GetParam() /* uses gestures */) {
+  if (GetParam().use_touch_gestures) {
     event_generator->GestureTapAt(window_center);
   } else {
     event_generator->MoveMouseTo(window_center);
@@ -1656,8 +1680,7 @@
   EXPECT_EQ(desk_2, desk_2_mini_view->desk());
   DragItemToPoint(overview_item,
                   desk_2_mini_view->GetBoundsInScreen().CenterPoint(),
-                  GetEventGenerator(),
-                  /*by_touch_gestures=*/GetParam());
+                  GetEventGenerator(), GetParam().use_touch_gestures);
   EXPECT_TRUE(overview_controller->InOverviewSession());
   EXPECT_TRUE(overview_grid->empty());
   EXPECT_TRUE(base::Contains(desk_2->windows(), window.get()));
@@ -1687,8 +1710,7 @@
                       ->mini_views()[1]
                       ->GetBoundsInScreen()
                       .CenterPoint(),
-                  GetEventGenerator(),
-                  /*by_touch_gestures=*/GetParam());
+                  GetEventGenerator(), GetParam().use_touch_gestures);
   EXPECT_FALSE(DoesActiveDeskContainWindow(win.get()));
   ASSERT_TRUE(overview_controller->InOverviewSession());
   EXPECT_TRUE(overview_session->IsEmpty());
@@ -1723,15 +1745,14 @@
   // nothing should happen.
   DragItemToPoint(overview_item,
                   window->GetRootWindow()->GetBoundsInScreen().bottom_center(),
-                  GetEventGenerator(),
-                  /*by_touch_gestures=*/GetParam());
+                  GetEventGenerator(), GetParam().use_touch_gestures);
   EXPECT_TRUE(overview_controller->InOverviewSession());
   EXPECT_EQ(1u, overview_grid->size());
   EXPECT_EQ(target_bounds_before_drag, overview_item->target_bounds());
   EXPECT_TRUE(DoesActiveDeskContainWindow(window.get()));
 }
 
-TEST_F(DesksTest, MruWindowTracker) {
+TEST_P(DesksTest, MruWindowTracker) {
   // Create two desks with two windows in each.
   auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
   auto win1 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
@@ -1776,7 +1797,7 @@
   EXPECT_EQ(win0.get(), window_list[3]);
 }
 
-TEST_F(DesksTest, NextActivatable) {
+TEST_P(DesksTest, NextActivatable) {
   // Create two desks with two windows in each.
   auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
   auto win1 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
@@ -1807,7 +1828,7 @@
   EXPECT_EQ(nullptr, window_util::GetActiveWindow());
 }
 
-TEST_F(DesksTest, NoMiniViewsUpdateOnOverviewEnter) {
+TEST_P(DesksTest, NoMiniViewsUpdateOnOverviewEnter) {
   auto* controller = DesksController::Get();
   NewDesk();
   ASSERT_EQ(2u, controller->desks().size());
@@ -1840,7 +1861,7 @@
 }
 
 // Tests that the consecutive daily visits metric is properly recorded.
-TEST_F(DesksTest, ConsecutiveDailyVisitsMetric) {
+TEST_P(DesksTest, ConsecutiveDailyVisitsMetric) {
   constexpr char kConsecutiveDailyVisitsHistogram[] =
       "Ash.Desks.ConsecutiveDailyVisits";
   auto* desks_controller = DesksController::Get();
@@ -1909,7 +1930,7 @@
 }
 
 // Tests that the new desk button's state and color are as expected.
-TEST_F(DesksTest, NewDeskButtonStateAndColor) {
+TEST_P(DesksTest, NewDeskButtonStateAndColor) {
   auto* controller = DesksController::Get();
   NewDesk();
   ASSERT_EQ(2u, controller->desks().size());
@@ -1921,6 +1942,7 @@
   ASSERT_TRUE(desks_bar_view);
   const auto* new_desk_button =
       desks_bar_view->expanded_state_new_desk_button()->inner_button();
+  auto* scroll_right_button = DesksTestApi::GetDesksBarRightScrollButton();
 
   // Tests that with one or two desks, the new desk button has an enabled state
   // and color.
@@ -1944,6 +1966,7 @@
     ClickOnView(new_desk_button, event_generator);
     EXPECT_EQ(prev_size + 1, controller->desks().size());
     prev_size = controller->desks().size();
+    ClickOnView(scroll_right_button, event_generator);
   }
   EXPECT_FALSE(new_desk_button->GetEnabled());
   EXPECT_EQ(disabled_background_color,
@@ -1952,7 +1975,7 @@
 
 // Tests that the fullscreen state in shell is updated when switching between
 // desks that have active windows in different fullscreen states.
-TEST_F(DesksTest, FullscreenStateUpdatedAcrossDesks) {
+TEST_P(DesksTest, FullscreenStateUpdatedAcrossDesks) {
   FullScreenStateObserver full_screen_state_observer;
   auto* controller = DesksController::Get();
   WMEvent event_toggle_fullscreen(WM_EVENT_TOGGLE_FULLSCREEN);
@@ -1996,7 +2019,7 @@
 }
 
 // Tests the Ash.Desks.AnimationLatency.DeskActivation histogram.
-TEST_F(DesksTest, AnimationLatencyDeskActivation) {
+TEST_P(DesksTest, AnimationLatencyDeskActivation) {
   NewDesk();
   auto* controller = DesksController::Get();
   ASSERT_EQ(2u, controller->desks().size());
@@ -2008,7 +2031,7 @@
 }
 
 // Tests the Ash.Desks.AnimationLatency.DeskRemoval histogram.
-TEST_F(DesksTest, AnimationLatencyDeskRemoval) {
+TEST_P(DesksTest, AnimationLatencyDeskRemoval) {
   NewDesk();
   auto* controller = DesksController::Get();
   ASSERT_EQ(2u, controller->desks().size());
@@ -2278,7 +2301,7 @@
   const DesksBarView* desks_bar_view_ = nullptr;
 };
 
-TEST_F(DesksEditableNamesTest, DefaultNameChangeAborted) {
+TEST_P(DesksEditableNamesTest, DefaultNameChangeAborted) {
   ASSERT_EQ(2u, controller()->desks().size());
   ASSERT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
 
@@ -2302,7 +2325,7 @@
                          {std::string(), std::string()});
 }
 
-TEST_F(DesksEditableNamesTest, NamesSetByUsersAreNotOverwritten) {
+TEST_P(DesksEditableNamesTest, NamesSetByUsersAreNotOverwritten) {
   ASSERT_EQ(2u, controller()->desks().size());
   ASSERT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
 
@@ -2366,7 +2389,7 @@
   EXPECT_EQ(u"Desk 2", desk_3->name());
 }
 
-TEST_F(DesksEditableNamesTest, DontAllowEmptyNames) {
+TEST_P(DesksEditableNamesTest, DontAllowEmptyNames) {
   ASSERT_EQ(2u, controller()->desks().size());
   ASSERT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
 
@@ -2386,7 +2409,7 @@
                          {std::string(), std::string()});
 }
 
-TEST_F(DesksEditableNamesTest, RevertDeskNameOnEscape) {
+TEST_P(DesksEditableNamesTest, RevertDeskNameOnEscape) {
   ASSERT_EQ(2u, controller()->desks().size());
   ASSERT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
 
@@ -2404,7 +2427,7 @@
   EXPECT_EQ(u"Desk 1", desk_1->name());
 }
 
-TEST_F(DesksEditableNamesTest, SelectAllOnFocus) {
+TEST_P(DesksEditableNamesTest, SelectAllOnFocus) {
   ASSERT_EQ(2u, controller()->desks().size());
   ASSERT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
   ClickOnDeskNameViewAtIndex(0);
@@ -2416,7 +2439,7 @@
   EXPECT_EQ(desk_1->name(), desk_name_view->GetSelectedText());
 }
 
-TEST_F(DesksEditableNamesTest, EventsThatCommitChanges) {
+TEST_P(DesksEditableNamesTest, EventsThatCommitChanges) {
   ASSERT_EQ(2u, controller()->desks().size());
   ASSERT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
   ClickOnDeskNameViewAtIndex(0);
@@ -2447,7 +2470,7 @@
   ASSERT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
 }
 
-TEST_F(DesksEditableNamesTest, MaxLength) {
+TEST_P(DesksEditableNamesTest, MaxLength) {
   ASSERT_EQ(2u, controller()->desks().size());
   ASSERT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
 
@@ -2511,7 +2534,7 @@
   }
 };
 
-TEST_F(TabletModeDesksTest, Backdrops) {
+TEST_P(TabletModeDesksTest, Backdrops) {
   auto* controller = DesksController::Get();
   NewDesk();
   ASSERT_EQ(2u, controller->desks().size());
@@ -2584,7 +2607,7 @@
   EXPECT_FALSE(desk_2_backdrop_controller->backdrop_window());
 }
 
-TEST_F(TabletModeDesksTest,
+TEST_P(TabletModeDesksTest,
        BackdropStackingAndMiniviewsUpdatesWithOverviewDragDrop) {
   auto* controller = DesksController::Get();
   NewDesk();
@@ -2654,7 +2677,7 @@
   desk_2->RemoveObserver(&observer2);
 }
 
-TEST_F(TabletModeDesksTest, NoDesksBarInTabletModeWithOneDesk) {
+TEST_P(TabletModeDesksTest, NoDesksBarInTabletModeWithOneDesk) {
   // Initially there's only one desk.
   auto* controller = DesksController::Get();
   ASSERT_EQ(1u, controller->desks().size());
@@ -2692,7 +2715,7 @@
   ASSERT_EQ(2u, desks_bar_view->mini_views().size());
 }
 
-TEST_F(TabletModeDesksTest, DesksCreationRemovalCycle) {
+TEST_P(TabletModeDesksTest, DesksCreationRemovalCycle) {
   auto window = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
   wm::ActivateWindow(window.get());
   EXPECT_EQ(window.get(), window_util::GetActiveWindow());
@@ -2701,7 +2724,7 @@
   // containers are reused for new desks, their backdrop state are always
   // correct, and there are no crashes as desks are removed.
   auto* desks_controller = DesksController::Get();
-  for (size_t i = 0; i < 2 * desks_util::kMaxNumberOfDesks; ++i) {
+  for (size_t i = 0; i < 2 * desks_util::GetMaxNumberOfDesks(); ++i) {
     NewDesk();
     ASSERT_EQ(2u, desks_controller->desks().size());
     const Desk* desk_1 = desks_controller->desks()[0].get();
@@ -2730,7 +2753,7 @@
   }
 }
 
-TEST_F(TabletModeDesksTest, RestoreSplitViewOnDeskSwitch) {
+TEST_P(TabletModeDesksTest, RestoreSplitViewOnDeskSwitch) {
   // Create two desks with two snapped windows in each.
   auto* desks_controller = DesksController::Get();
   NewDesk();
@@ -2774,7 +2797,7 @@
   EXPECT_TRUE(WindowState::Get(win4.get())->IsSnapped());
 }
 
-TEST_F(TabletModeDesksTest, SnappedStateRetainedOnSwitchingDesksFromOverview) {
+TEST_P(TabletModeDesksTest, SnappedStateRetainedOnSwitchingDesksFromOverview) {
   auto* desks_controller = DesksController::Get();
   NewDesk();
   ASSERT_EQ(2u, desks_controller->desks().size());
@@ -2837,7 +2860,7 @@
   EXPECT_FALSE(overview_controller->InOverviewSession());
 }
 
-TEST_F(
+TEST_P(
     TabletModeDesksTest,
     SnappedStateRetainedOnSwitchingDesksWithOverviewFullOfUnsnappableWindows) {
   auto* desks_controller = DesksController::Get();
@@ -2903,7 +2926,7 @@
   EXPECT_TRUE(overview_controller->InOverviewSession());
 }
 
-TEST_F(TabletModeDesksTest, OverviewStateOnSwitchToDeskWithSplitView) {
+TEST_P(TabletModeDesksTest, OverviewStateOnSwitchToDeskWithSplitView) {
   // Setup two desks, one (desk_1) with two snapped windows, and the other
   // (desk_2) with only one snapped window.
   auto* desks_controller = DesksController::Get();
@@ -2940,7 +2963,7 @@
   EXPECT_FALSE(overview_controller->InOverviewSession());
 }
 
-TEST_F(TabletModeDesksTest, RemovingDesksWithSplitView) {
+TEST_P(TabletModeDesksTest, RemovingDesksWithSplitView) {
   auto* desks_controller = DesksController::Get();
   NewDesk();
   ASSERT_EQ(2u, desks_controller->desks().size());
@@ -2965,7 +2988,7 @@
             split_view_controller()->state());
 }
 
-TEST_F(TabletModeDesksTest, RemoveDeskWithMaximizedWindowAndMergeWithSnapped) {
+TEST_P(TabletModeDesksTest, RemoveDeskWithMaximizedWindowAndMergeWithSnapped) {
   auto* desks_controller = DesksController::Get();
   NewDesk();
   ASSERT_EQ(2u, desks_controller->desks().size());
@@ -2993,7 +3016,7 @@
 
 // Tests that closing the active desk while in overview does not quit overview.
 // Regression test for https://crbug.com/1309175.
-TEST_F(TabletModeDesksTest, RemovingActiveDeskDoesNotExitOverview) {
+TEST_P(TabletModeDesksTest, RemovingActiveDeskDoesNotExitOverview) {
   auto* desks_controller = DesksController::Get();
   NewDesk();
   ASSERT_EQ(2u, desks_controller->desks().size());
@@ -3009,7 +3032,7 @@
   EXPECT_TRUE(overview_controller->InOverviewSession());
 }
 
-TEST_F(TabletModeDesksTest, BackdropsStacking) {
+TEST_P(TabletModeDesksTest, BackdropsStacking) {
   auto* desks_controller = DesksController::Get();
   NewDesk();
   ASSERT_EQ(2u, desks_controller->desks().size());
@@ -3057,7 +3080,7 @@
   EXPECT_TRUE(IsStackedBelow(desk_2_backdrop, win4.get()));
 }
 
-TEST_F(TabletModeDesksTest, HotSeatStateAfterMovingAWindowToAnotherDesk) {
+TEST_P(TabletModeDesksTest, HotSeatStateAfterMovingAWindowToAnotherDesk) {
   // Create 2 desks, and 2 windows, one of them is minimized and the other is
   // normal. Test that dragging and dropping them to another desk does not hide
   // the hotseat. https://crbug.com/1063536.
@@ -3119,7 +3142,7 @@
   }
 }
 
-TEST_F(TabletModeDesksTest, RestoringUnsnappableWindowsInSplitView) {
+TEST_P(TabletModeDesksTest, RestoringUnsnappableWindowsInSplitView) {
   UpdateDisplay("600x400");
   display::test::DisplayManagerTestApi(display_manager())
       .SetFirstDisplayAsInternalDisplay();
@@ -3171,7 +3194,7 @@
   EXPECT_TRUE(WindowState::Get(window.get())->IsMaximized());
 }
 
-TEST_F(DesksTest, MiniViewsTouchGestures) {
+TEST_P(DesksTest, MiniViewsTouchGestures) {
   // TODO(crbug.com/1361138): Figure out how to accommodate the context menu in
   // CloseAll.
   base::test::ScopedFeatureList desks_close_all_disabler;
@@ -3225,7 +3248,7 @@
   EXPECT_TRUE(controller->desks()[0]->is_active());
 }
 
-TEST_F(DesksTest, AutohiddenShelfAnimatesAfterDeskSwitch) {
+TEST_P(DesksTest, AutohiddenShelfAnimatesAfterDeskSwitch) {
   Shelf* shelf = GetPrimaryShelf();
   ShelfWidget* shelf_widget = shelf->shelf_widget();
   const gfx::Rect shown_shelf_bounds = shelf_widget->GetWindowBoundsInScreen();
@@ -3268,7 +3291,7 @@
   EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState());
 }
 
-TEST_F(DesksTest, SwitchToDeskWithSnappedActiveWindow) {
+TEST_P(DesksTest, SwitchToDeskWithSnappedActiveWindow) {
   auto* desks_controller = DesksController::Get();
   auto* overview_controller = Shell::Get()->overview_controller();
 
@@ -3301,7 +3324,7 @@
   EXPECT_FALSE(overview_controller->InOverviewSession());
 }
 
-TEST_F(DesksTest, SuccessfulDragToDeskRemovesSplitViewIndicators) {
+TEST_P(DesksTest, SuccessfulDragToDeskRemovesSplitViewIndicators) {
   auto* controller = DesksController::Get();
   NewDesk();
   ASSERT_EQ(2u, controller->desks().size());
@@ -3351,7 +3374,7 @@
                 ->current_window_dragging_state());
 }
 
-TEST_F(DesksTest, DragAllOverviewWindowsToOtherDesksNotEndClamshellSplitView) {
+TEST_P(DesksTest, DragAllOverviewWindowsToOtherDesksNotEndClamshellSplitView) {
   // Two virtual desks.
   NewDesk();
   ASSERT_EQ(2u, DesksController::Get()->desks().size());
@@ -3386,7 +3409,7 @@
   EXPECT_TRUE(split_view_controller->InSplitViewMode());
 }
 
-TEST_F(DesksTest, DeskTraversalNonTouchpadMetrics) {
+TEST_P(DesksTest, DeskTraversalNonTouchpadMetrics) {
   NewDesk();
   NewDesk();
   NewDesk();
@@ -3417,7 +3440,7 @@
 
 // Tests that clipping is unchanged when removing a desk in overview. Regression
 // test for https://crbug.com/1166300.
-TEST_F(DesksTest, RemoveDeskPreservesOverviewClipping) {
+TEST_P(DesksTest, RemoveDeskPreservesOverviewClipping) {
   // Three virtual desks.
   NewDesk();
   NewDesk();
@@ -3963,12 +3986,12 @@
 
 namespace {
 
-TEST_F(DesksAcceleratorsTest, NewDesk) {
+TEST_P(DesksAcceleratorsTest, NewDesk) {
   auto* controller = DesksController::Get();
   // It's possible to add up to kMaxNumberOfDesks desks using the
   // shortcut.
   const int flags = ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN;
-  for (size_t num_desks = 1; num_desks < desks_util::kMaxNumberOfDesks;
+  for (size_t num_desks = 1; num_desks < desks_util::GetMaxNumberOfDesks();
        ++num_desks) {
     DeskSwitchAnimationWaiter waiter;
     SendAccelerator(ui::VKEY_OEM_PLUS, flags);
@@ -3979,12 +4002,12 @@
   }
 
   // When we reach the limit, the shortcut does nothing.
-  EXPECT_EQ(desks_util::kMaxNumberOfDesks, controller->desks().size());
+  EXPECT_EQ(desks_util::GetMaxNumberOfDesks(), controller->desks().size());
   SendAccelerator(ui::VKEY_OEM_PLUS, flags);
-  EXPECT_EQ(desks_util::kMaxNumberOfDesks, controller->desks().size());
+  EXPECT_EQ(desks_util::GetMaxNumberOfDesks(), controller->desks().size());
 }
 
-TEST_F(DesksAcceleratorsTest, CannotRemoveLastDesk) {
+TEST_P(DesksAcceleratorsTest, CannotRemoveLastDesk) {
   auto* controller = DesksController::Get();
   // Removing the last desk is not possible.
   ASSERT_EQ(1u, controller->desks().size());
@@ -3993,7 +4016,7 @@
   ASSERT_EQ(1u, controller->desks().size());
 }
 
-TEST_F(DesksAcceleratorsTest, RemoveDesk) {
+TEST_P(DesksAcceleratorsTest, RemoveDesk) {
   auto* controller = DesksController::Get();
   // Create a few desks and remove them outside and inside overview using the
   // shortcut.
@@ -4021,7 +4044,7 @@
   EXPECT_TRUE(overview_controller->InOverviewSession());
 }
 
-TEST_F(DesksAcceleratorsTest, RemoveRightmostDesk) {
+TEST_P(DesksAcceleratorsTest, RemoveRightmostDesk) {
   auto* controller = DesksController::Get();
   // Create a few desks and remove them outside and inside overview using the
   // shortcut.
@@ -4050,7 +4073,7 @@
   EXPECT_TRUE(desk_1->is_active());
 }
 
-TEST_F(DesksAcceleratorsTest, LeftRightDeskActivation) {
+TEST_P(DesksAcceleratorsTest, LeftRightDeskActivation) {
   auto* controller = DesksController::Get();
   NewDesk();
   ASSERT_EQ(2u, controller->desks().size());
@@ -4083,7 +4106,7 @@
   }
 }
 
-TEST_F(DesksAcceleratorsTest, MoveWindowLeftRightDesk) {
+TEST_P(DesksAcceleratorsTest, MoveWindowLeftRightDesk) {
   auto* controller = DesksController::Get();
   NewDesk();
   ASSERT_EQ(2u, controller->desks().size());
@@ -4126,7 +4149,7 @@
   EXPECT_TRUE(base::Contains(desk_1->windows(), window.get()));
 }
 
-TEST_F(DesksAcceleratorsTest, MoveWindowLeftRightDeskOverview) {
+TEST_P(DesksAcceleratorsTest, MoveWindowLeftRightDeskOverview) {
   auto* controller = DesksController::Get();
   NewDesk();
   ASSERT_EQ(2u, controller->desks().size());
@@ -4175,7 +4198,7 @@
   EXPECT_FALSE(overview_session->GetHighlightedWindow());
 }
 
-TEST_F(DesksAcceleratorsTest, CannotMoveAlwaysOnTopWindows) {
+TEST_P(DesksAcceleratorsTest, CannotMoveAlwaysOnTopWindows) {
   auto* controller = DesksController::Get();
   NewDesk();
   ASSERT_EQ(2u, controller->desks().size());
@@ -4206,7 +4229,7 @@
 
 // Tests that hitting an acclerator to switch desks does not cause a crash if we
 // are already at an edge desk. Regression test for https://crbug.com/1159068.
-TEST_F(DesksAcceleratorsTest, HitAcceleratorWhenAlreadyAtEdge) {
+TEST_P(DesksAcceleratorsTest, HitAcceleratorWhenAlreadyAtEdge) {
   NewDesk();
 
   // Enable animations so that we can make sure that they occur.
@@ -4235,7 +4258,7 @@
 
 // Tests that the assign to all desks shortcut works as expected and that its
 // metrics are recorded properly.
-TEST_F(DesksAcceleratorsTest, AssignToAllDesksShortcut) {
+TEST_P(DesksAcceleratorsTest, AssignToAllDesksShortcut) {
   base::HistogramTester histogram_tester;
 
   // Create two new desks.
@@ -4274,7 +4297,7 @@
 }
 
 // Tests that the indexed-desk activation keyboard shortcut works properly.
-TEST_F(DesksAcceleratorsTest, IndexedDeskActivationShortcut) {
+TEST_P(DesksAcceleratorsTest, IndexedDeskActivationShortcut) {
   const int flags = ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN;
   constexpr char kDesksSwitchHistogramName[] = "Ash.Desks.DesksSwitch";
   base::HistogramTester histogram_tester;
@@ -4572,8 +4595,7 @@
 
 // Tests desks name nudges, i.e. when a user creates a new desk, focus + clear
 // the new desk's renaming textfield.
-TEST_F(DesksTest, NameNudges) {
-  // Make sure the display is large enough to hold the max number of desks.
+TEST_P(DesksTest, NameNudges) {
   UpdateDisplay("1200x800");
   auto* controller = DesksController::Get();
 
@@ -4596,11 +4618,15 @@
       desks_bar_view->expanded_state_new_desk_button()->inner_button();
   EXPECT_TRUE(new_desk_button->GetEnabled());
 
+  // As desks are added, we will scroll the desks bar to keep the "new desk"
+  // button in view.
+  auto* scroll_right_button = DesksTestApi::GetDesksBarRightScrollButton();
+
   // Click on the new desk button until the max number of desks is created. Each
   // time a new desk is created the new desk's name view should have focus, be
   // empty and have its accessible name set to the default desk name. Also, the
   // previous desk should be left with a default name.
-  for (size_t i = 1; i < desks_util::kMaxNumberOfDesks; ++i) {
+  for (size_t i = 1; i < desks_util::GetMaxNumberOfDesks(); ++i) {
     ClickOnView(new_desk_button, event_generator);
     auto* desk_name_view = desks_bar_view->mini_views()[i]->desk_name_view();
     EXPECT_TRUE(desk_name_view->HasFocus());
@@ -4609,6 +4635,7 @@
               desk_name_view->GetAccessibleName());
     EXPECT_EQ(DesksController::GetDeskDefaultName(i - 1),
               controller->desks()[i - 1]->name());
+    ClickOnView(scroll_right_button, event_generator);
   }
 }
 
@@ -4616,7 +4643,7 @@
 // clicks/touches the new desk button, the newly created DeskNameView that
 // resides on the same DesksBarView as the clicked button should be focused.
 // See crbug.com/1206013.
-TEST_F(DesksTest, NameNudgesMultiDisplay) {
+TEST_P(DesksTest, NameNudgesMultiDisplay) {
   UpdateDisplay("800x700,800x700");
 
   // Start overview.
@@ -4693,7 +4720,7 @@
 // Tests that when a user has a `DeskNameView` focused and clicks within the
 // overview grid, the `DeskNameView` loses focus and the overview grid is not
 // closed.
-TEST_F(DesksTest, ClickingOverviewGridUnfocusesDeskNameView) {
+TEST_P(DesksTest, ClickingOverviewGridUnfocusesDeskNameView) {
   // Create a second desk so we don't start in zero state.
   NewDesk();
 
@@ -4720,7 +4747,7 @@
   EXPECT_TRUE(overview_controller->InOverviewSession());
 }
 
-TEST_F(DesksTest, ScrollableDesks) {
+TEST_P(DesksTest, ScrollableDesks) {
   UpdateDisplay("201x400");
   EnterOverview();
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
@@ -4739,11 +4766,11 @@
 
   // Set the scroll delta large enough to make sure the desks bar can be
   // scrolled to the end each time.
-  const int x_scroll_delta = 200;
+  const int x_scroll_delta = 400;
   gfx::Rect display_bounds =
       screen_util::GetDisplayWorkAreaBoundsInScreenForActiveDeskContainer(
           root_window);
-  for (size_t i = 1; i < desks_util::kMaxNumberOfDesks; i++) {
+  for (size_t i = 1; i < desks_util::GetMaxNumberOfDesks(); i++) {
     gfx::Rect new_desk_button_bounds = new_desk_button->GetBoundsInScreen();
     EXPECT_TRUE(display_bounds.Contains(new_desk_button_bounds));
     ClickOnView(new_desk_button, event_generator);
@@ -4753,7 +4780,7 @@
   }
 
   auto* controller = DesksController::Get();
-  EXPECT_EQ(desks_util::kMaxNumberOfDesks, controller->desks().size());
+  EXPECT_EQ(desks_util::GetMaxNumberOfDesks(), controller->desks().size());
   EXPECT_FALSE(controller->CanCreateDesks());
 
   EXPECT_TRUE(display_bounds.Contains(new_desk_button->GetBoundsInScreen()));
@@ -4768,13 +4795,13 @@
 
 // Tests the visibility of the scroll buttons and behavior while clicking the
 // corresponding scroll button.
-TEST_F(DesksTest, ScrollButtonsVisibility) {
+TEST_P(DesksTest, ScrollButtonsVisibility) {
   UpdateDisplay("501x600");
-  for (size_t i = 1; i < desks_util::kMaxNumberOfDesks; i++)
+  for (size_t i = 1; i < desks_util::GetMaxNumberOfDesks(); i++)
     NewDesk();
 
   EXPECT_EQ(DesksController::Get()->desks().size(),
-            desks_util::kMaxNumberOfDesks);
+            desks_util::GetMaxNumberOfDesks());
   auto window = CreateAppWindow(gfx::Rect(0, 0, 100, 100));
   TabletModeControllerTestApi().EnterTabletMode();
   // Snap the window to left and then right side of the display should enter
@@ -4789,7 +4816,7 @@
 
   // Set the scroll delta large enough to make sure the desks bar can be
   // scrolled to the end each time.
-  const int x_scroll_delta = 500;
+  const int x_scroll_delta = 1000;
   // Left scroll button should be hidden and right scroll button should be
   // visible while at the start position.
   event_generator->MoveMouseWheel(x_scroll_delta, 0);
@@ -4817,11 +4844,11 @@
   EXPECT_FALSE(DesksTestApi::GetDesksBarRightScrollButton()->GetVisible());
 }
 
-TEST_F(DesksTest, GradientsVisibility) {
+TEST_P(DesksTest, GradientsVisibility) {
   // Set a flat display size to make sure there are multiple pages in the desks
   // bar with maximum number of desks.
   UpdateDisplay("800x150");
-  const size_t max_desks_size = desks_util::kMaxNumberOfDesks;
+  const size_t max_desks_size = desks_util::GetMaxNumberOfDesks();
   for (size_t i = 1; i < max_desks_size; i++)
     NewDesk();
 
@@ -4901,10 +4928,10 @@
 }
 
 // Tests the behavior when long press on the scroll buttons.
-TEST_F(DesksTest, ContinueScrollBar) {
+TEST_P(DesksTest, ContinueScrollBar) {
   // Make a flat long window to generate multiple pages on desks bar.
   UpdateDisplay("800x150");
-  const size_t max_desks_size = desks_util::kMaxNumberOfDesks;
+  const size_t max_desks_size = desks_util::GetMaxNumberOfDesks();
   for (size_t i = 1; i < max_desks_size; i++)
     NewDesk();
 
@@ -4954,8 +4981,11 @@
   EXPECT_EQ(scroll_view->GetVisibleRect().x(),
             mini_views[current_index]->bounds().x());
 
-  // Wait for 1s, it will scroll to the maximum offset. Scroll ends.
-  WaitForMilliseconds(1000);
+  // Release and click a few times to make sure we end up at the maximum offset.
+  event_generator->ReleaseLeftButton();
+  for (int i = 0; i != 3; ++i)
+    event_generator->ClickLeftButton();
+
   EXPECT_EQ(scroll_view->GetVisibleRect().x(),
             scroll_view->contents()->width() - page_size);
 
@@ -4964,7 +4994,9 @@
   EXPECT_TRUE(left_button->GetVisible());
   EXPECT_FALSE(right_button->GetVisible());
 
-  event_generator->ReleaseLeftButton();
+  // Since we're scrolled all the way to the right and the new desk button is
+  // visible, this is the index of the leftmost visible mini view.
+  current_index = max_desks_size - desks_in_one_page + 1;
 
   // Press on left scroll button by gesture should scroll to the previous page.
   // And the final scroll position should also be adjusted while scrolling to
@@ -4986,13 +5018,13 @@
 
 // Tests that change the focused mini view should scroll the desks bar and put
 // the focused mini view inside the visible bounds.
-TEST_F(DesksTest, FocusedMiniViewIsVisible) {
+TEST_P(DesksTest, FocusedMiniViewIsVisible) {
   UpdateDisplay("501x600");
-  for (size_t i = 1; i < desks_util::kMaxNumberOfDesks; i++)
+  for (size_t i = 1; i < desks_util::GetMaxNumberOfDesks(); i++)
     NewDesk();
 
   EXPECT_EQ(DesksController::Get()->desks().size(),
-            desks_util::kMaxNumberOfDesks);
+            desks_util::GetMaxNumberOfDesks());
   auto window = CreateAppWindow(gfx::Rect(0, 0, 100, 100));
   TabletModeControllerTestApi().EnterTabletMode();
   // Snap the window to left and then right side of the display should enter
@@ -5003,9 +5035,9 @@
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
   auto* desks_bar = GetOverviewGridForRoot(root_window)->desks_bar_view();
   auto mini_views = desks_bar->mini_views();
-  ASSERT_EQ(mini_views.size(), desks_util::kMaxNumberOfDesks);
+  ASSERT_EQ(mini_views.size(), desks_util::GetMaxNumberOfDesks());
   // Traverse all the desks mini views from left to right.
-  for (size_t i = 0; i < desks_util::kMaxNumberOfDesks; i++) {
+  for (size_t i = 0; i < desks_util::GetMaxNumberOfDesks(); i++) {
     // Move the focus to the mini view's associated preview view.
     SendKey(ui::VKEY_TAB);
     EXPECT_TRUE(
@@ -5016,7 +5048,7 @@
   }
 
   // Traverse from all the desk mini views from right to left.
-  for (size_t i = desks_util::kMaxNumberOfDesks - 1; i > 0; i--) {
+  for (size_t i = desks_util::GetMaxNumberOfDesks() - 1; i > 0; i--) {
     // Move the focus from desk name view to the associated preview view.
     SendKey(ui::VKEY_LEFT);
     // Move the focus to previous mini view's name view.
@@ -5029,7 +5061,7 @@
 
 // Tests that the bounds of a window that is visible on all desks is shared
 // across desks.
-TEST_F(DesksTest, VisibleOnAllDesksGlobalBounds) {
+TEST_P(DesksTest, VisibleOnAllDesksGlobalBounds) {
   auto* controller = DesksController::Get();
   NewDesk();
   const Desk* desk_1 = controller->desks()[0].get();
@@ -5069,7 +5101,7 @@
 
 // Tests that the z-ordering of windows that are visible on all desks respects
 // its global MRU ordering.
-TEST_F(DesksTest, VisibleOnAllDesksGlobalZOrder) {
+TEST_P(DesksTest, VisibleOnAllDesksGlobalZOrder) {
   auto* controller = DesksController::Get();
   NewDesk();
   const Desk* desk_1 = controller->desks()[0].get();
@@ -5130,7 +5162,7 @@
 
 // Tests the behavior of windows that are visible on all desks when the active
 // desk is removed.
-TEST_F(DesksTest, VisibleOnAllDesksActiveDeskRemoval) {
+TEST_P(DesksTest, VisibleOnAllDesksActiveDeskRemoval) {
   auto* controller = DesksController::Get();
   NewDesk();
   const Desk* desk_1 = controller->desks()[0].get();
@@ -5158,7 +5190,7 @@
 }
 
 // Tests the behavior of a minimized window that is visible on all desks.
-TEST_F(DesksTest, VisibleOnAllDesksMinimizedWindow) {
+TEST_P(DesksTest, VisibleOnAllDesksMinimizedWindow) {
   auto* controller = DesksController::Get();
   NewDesk();
   const Desk* desk_2 = controller->desks()[1].get();
@@ -5186,7 +5218,7 @@
 
 // Tests the behavior of a window that is visible on all desks when a user tries
 // to move it to another desk using drag and drop (overview mode).
-TEST_F(DesksTest, VisibleOnAllDesksMoveWindowToDeskViaDragAndDrop) {
+TEST_P(DesksTest, VisibleOnAllDesksMoveWindowToDeskViaDragAndDrop) {
   auto* controller = DesksController::Get();
   auto* root = Shell::GetPrimaryRootWindow();
   NewDesk();
@@ -5212,7 +5244,7 @@
 
 // Tests the behavior of a window that is visible on all desks when a user tries
 // to move it to another desk using keyboard shortcuts.
-TEST_F(DesksTest, VisibleOnAllDesksMoveWindowToDeskViaShortcuts) {
+TEST_P(DesksTest, VisibleOnAllDesksMoveWindowToDeskViaShortcuts) {
   auto* controller = DesksController::Get();
   auto* root = Shell::GetPrimaryRootWindow();
   NewDesk();
@@ -5238,7 +5270,7 @@
 
 // Tests the behavior of a window that is visible on all desks when a user tries
 // to move it using the context menu.
-TEST_F(DesksTest, VisibleOnAllDesksMoveWindowToDeskViaContextMenu) {
+TEST_P(DesksTest, VisibleOnAllDesksMoveWindowToDeskViaContextMenu) {
   auto* controller = DesksController::Get();
   NewDesk();
   const Desk* desk_2 = controller->desks()[1].get();
@@ -5261,7 +5293,7 @@
 
 // Tests that when a window that is visible on all desks is destroyed it is
 // removed from DesksController.visible_on_all_desks_windows_.
-TEST_F(DesksTest, VisibleOnAllDesksWindowDestruction) {
+TEST_P(DesksTest, VisibleOnAllDesksWindowDestruction) {
   auto* controller = DesksController::Get();
   NewDesk();
   const Desk* desk_1 = controller->desks()[0].get();
@@ -5283,7 +5315,7 @@
   EXPECT_EQ(0u, desk_1->GetDeskContainerForRoot(root)->children().size());
 }
 
-TEST_F(DesksTest, EnterOverviewWithCorrectDesksBarState) {
+TEST_P(DesksTest, EnterOverviewWithCorrectDesksBarState) {
   auto* controller = DesksController::Get();
   ASSERT_EQ(1u, controller->desks().size());
   EnterOverview();
@@ -5310,7 +5342,7 @@
 }
 
 // Tests the behavior of desks bar zero state.
-TEST_F(DesksTest, DesksBarZeroState) {
+TEST_P(DesksTest, DesksBarZeroState) {
   EnterOverview();
 
   auto* root_window = Shell::GetPrimaryRootWindow();
@@ -5360,7 +5392,7 @@
 // Tests that buttons in the desk bar are shown and hidden correctly when
 // transitioning into zero state to ensure ChromeVox navigation works properly.
 // Regression test for https://crbug.com/1351501.
-TEST_F(DesksTest, DesksBarButtonVisibility) {
+TEST_P(DesksTest, DesksBarButtonVisibility) {
   auto* controller = DesksController::Get();
 
   // Create a new desk so when we enter overview mode the desks bar is in the
@@ -5402,7 +5434,7 @@
   EXPECT_TRUE(zero_state_default_desk_button->GetVisible());
 }
 
-TEST_F(DesksTest, NewDeskButton) {
+TEST_P(DesksTest, NewDeskButton) {
   auto* controller = DesksController::Get();
   EnterOverview();
 
@@ -5419,20 +5451,27 @@
   EXPECT_TRUE(new_desk_button->GetVisible());
   EXPECT_TRUE(new_desk_button->GetEnabled());
 
-  for (size_t i = 1; i < desks_util::kMaxNumberOfDesks; i++)
+  auto* scroll_right_button = DesksTestApi::GetDesksBarRightScrollButton();
+
+  for (size_t i = 1; i < desks_util::GetMaxNumberOfDesks(); i++) {
     ClickOnView(new_desk_button, event_generator);
+    ClickOnView(scroll_right_button, event_generator);
+  }
+
   // The new desk button should become disabled after maximum number of desks
   // have been created.
   EXPECT_FALSE(controller->CanCreateDesks());
   EXPECT_FALSE(new_desk_button->GetEnabled());
 
+  ASSERT_EQ(controller->desks().size(), desks_util::GetMaxNumberOfDesks());
+
   // The new desk button should become enabled again after removing a desk.
-  CloseDeskFromMiniView(desks_bar_view->mini_views()[0], event_generator);
+  CloseDeskFromMiniView(desks_bar_view->mini_views().back(), event_generator);
   EXPECT_TRUE(controller->CanCreateDesks());
   EXPECT_TRUE(new_desk_button->GetEnabled());
 }
 
-TEST_F(DesksTest, ZeroStateDeskButtonText) {
+TEST_P(DesksTest, ZeroStateDeskButtonText) {
   UpdateDisplay("1600x1200");
   EnterOverview();
 
@@ -5501,7 +5540,7 @@
                               base::CompareCase::SENSITIVE));
 }
 
-TEST_F(DesksTest, ReorderDesksByMouse) {
+TEST_P(DesksTest, ReorderDesksByMouse) {
   auto* desks_controller = DesksController::Get();
 
   EnterOverview();
@@ -5571,7 +5610,7 @@
   event_generator->ReleaseLeftButton();
 }
 
-TEST_F(DesksTest, ReorderDesksByGesture) {
+TEST_P(DesksTest, ReorderDesksByGesture) {
   // TODO(crbug.com/1361138): Figure out how to accommodate the context menu in
   // CloseAll.
   base::test::ScopedFeatureList desks_close_all_disabler;
@@ -5646,7 +5685,7 @@
   event_generator->ReleaseTouch();
 }
 
-TEST_F(DesksTest, ReorderDesksByKeyboard) {
+TEST_P(DesksTest, ReorderDesksByKeyboard) {
   auto* desks_controller = DesksController::Get();
 
   auto* overview_controller = Shell::Get()->overview_controller();
@@ -5728,7 +5767,7 @@
 }
 
 // Test reordering desks in RTL mode.
-TEST_F(DesksTest, ReorderDesksInRTLMode) {
+TEST_P(DesksTest, ReorderDesksInRTLMode) {
   // TODO(crbug.com/1361138): Figure out how to accommodate the context menu in
   // CloseAll.
   base::test::ScopedFeatureList desks_close_all_disabler;
@@ -5824,12 +5863,13 @@
 }
 
 // Tests the behavior when drag a desk on the scroll button.
-TEST_F(DesksTest, ScrollBarByDraggedDesk) {
+TEST_P(DesksTest, ScrollBarByDraggedDesk) {
   // Make a flat long window to generate multiple pages on desks bar.
   UpdateDisplay("800x150");
-  const size_t max_desks_size = desks_util::kMaxNumberOfDesks;
-  for (size_t i = 1; i < max_desks_size; i++)
+  const size_t max_desks_size = desks_util::GetMaxNumberOfDesks();
+  for (size_t i = 1; i < max_desks_size; i++) {
     NewDesk();
+  }
 
   auto* desks_controller = DesksController::Get();
   EXPECT_EQ(desks_controller->desks().size(), max_desks_size);
@@ -5884,8 +5924,9 @@
   // While scrolling, the desk cannot be reordered.
   EXPECT_EQ(0, desks_controller->GetDeskIndex(desk_0));
 
-  // Wait for 1s, it will scroll to the maximum offset. Scroll ends.
-  WaitForMilliseconds(1000);
+  // Wait longer, it will scroll to the maximum offset. When 16 desks are
+  // enabled, we need to allow more time for scrolling.
+  WaitForMilliseconds(GetParam().use_16_desks ? 4000 : 1000);
   EXPECT_EQ(scroll_view->GetVisibleRect().x(),
             scroll_view->contents()->width() - page_size);
 
@@ -5903,6 +5944,8 @@
   EXPECT_EQ(max_index, desks_controller->GetDeskIndex(desk_0));
   event_generator->ReleaseLeftButton();
 
+  current_index = max_desks_size - desks_in_one_page + 1;
+
   // Dragging the desk to left scroll button should scroll to the previous page.
   // And the final scroll position should also be adjusted while scrolling to
   // the previous page to make sure the desk preview will not be cropped.
@@ -5933,7 +5976,7 @@
 // Tests that while reordering desks by drag & drop, when a desk is snapping
 // back, click its target location won't cause any crashes.
 // Regression test of https://crbug.com/1171880.
-TEST_F(DesksTest, ClickTargetLocationOfDroppedDesk) {
+TEST_P(DesksTest, ClickTargetLocationOfDroppedDesk) {
   EnterOverview();
   ASSERT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
 
@@ -5966,7 +6009,7 @@
 
 // Tests that while reordering desks by drag & drop, when a desk is snapping
 // back, dragging a desk preview on the shelf will start a new drag.
-TEST_F(DesksTest, DragNewDeskWhileSnappingBack) {
+TEST_P(DesksTest, DragNewDeskWhileSnappingBack) {
   EnterOverview();
   ASSERT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
 
@@ -6002,7 +6045,7 @@
 // (2) removing a desk makes the dragged desk the only one left. Then, releasing
 // mouse or exiting overview will not have UAF issues
 // (https://crbug.com/1222120).
-TEST_F(DesksTest, RemoveDeskWhileDragging) {
+TEST_P(DesksTest, RemoveDeskWhileDragging) {
   EnterOverview();
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
 
@@ -6049,7 +6092,7 @@
 }
 
 // Regression test for the asan failure at https://crbug.com/1274641.
-TEST_F(DesksTest, DragMiniViewWhileRemoving) {
+TEST_P(DesksTest, DragMiniViewWhileRemoving) {
   NewDesk();
   NewDesk();
 
@@ -6086,7 +6129,7 @@
 
 // Tests that the right desk containers are visible when switching between desks
 // really fast. Regression test for https://crbug.com/1194757.
-TEST_F(DesksTest, FastDeskSwitches) {
+TEST_P(DesksTest, FastDeskSwitches) {
   // Add 3 more desks and add a couple windows on each one.
   CreateTestWindow();
   CreateTestWindow();
@@ -6128,7 +6171,7 @@
   // visible, but they should all be opaque.
   std::vector<aura::Window*> desk_containers =
       desks_util::GetDesksContainers(Shell::GetPrimaryRootWindow());
-  ASSERT_EQ(8u, desk_containers.size());
+  ASSERT_EQ(desks_util::GetMaxNumberOfDesks(), desk_containers.size());
   EXPECT_TRUE(desk_containers[0]->IsVisible());
   EXPECT_EQ(1.f, desk_containers[0]->layer()->opacity());
 
@@ -6141,7 +6184,7 @@
 
 // Tests that when the user is in tablet mode, the virtual keyboard is opened
 // during name nudges.
-TEST_F(DesksTest, NameNudgesTabletMode) {
+TEST_P(DesksTest, NameNudgesTabletMode) {
   TabletModeControllerTestApi().EnterTabletMode();
 
   // Tablet mode requires at least two desks so create one.
@@ -6197,7 +6240,7 @@
 }
 
 // Tests the time period to set perf `kUserHasUsedDesksRecently`.
-TEST_F(DesksTest, PrimaryUserHasUsedDesksRecently) {
+TEST_P(DesksTest, PrimaryUserHasUsedDesksRecently) {
   base::SimpleTestClock test_clock;
   base::Time time;
   auto* desks_controller = DesksController::Get();
@@ -6233,7 +6276,7 @@
 
 // Tests that a desk's close button is visible in tablet mode after long
 // pressing on the desk's preview.
-TEST_F(DesksTest, CloseButtonShowsAfterLongPressInTabletMode) {
+TEST_P(DesksTest, CloseButtonShowsAfterLongPressInTabletMode) {
   base::test::ScopedFeatureList desks_close_all_disabler;
   desks_close_all_disabler.InitAndDisableFeature(features::kDesksCloseAll);
 
@@ -6272,7 +6315,7 @@
 };
 
 // Tests the visibility of the vertical dots button inside desks bar.
-TEST_F(DesksBentoBarTest, VerticalDotsButtonVisibility) {
+TEST_P(DesksBentoBarTest, VerticalDotsButtonVisibility) {
   ASSERT_FALSE(desks_restore_util::HasPrimaryUserUsedDesksRecently());
   EXPECT_TRUE(features::IsBentoBarEnabled());
 
@@ -6309,7 +6352,7 @@
 };
 
 // Tests that the weekly active desks metric is properly recorded.
-TEST_F(DesksMockTimeTest, WeeklyActiveDesks) {
+TEST_P(DesksMockTimeTest, WeeklyActiveDesks) {
   constexpr char kWeeklyActiveDesksHistogram[] = "Ash.Desks.WeeklyActiveDesks";
   base::HistogramTester histogram_tester;
 
@@ -6433,7 +6476,7 @@
 
 // Tests that the bar will only be created and shown when there are more than
 // one desk.
-TEST_F(PersistentDesksBarTest, MoreThanOneDesk) {
+TEST_P(PersistentDesksBarTest, MoreThanOneDesk) {
   auto* shell = Shell::Get();
   ASSERT_FALSE(shell->tablet_mode_controller()->InTabletMode());
   auto* desks_controller = DesksController::Get();
@@ -6458,7 +6501,7 @@
 }
 
 // Tests that the bar will only be created and shown in clamshell mode.
-TEST_F(PersistentDesksBarTest, ClamshellOnly) {
+TEST_P(PersistentDesksBarTest, ClamshellOnly) {
   auto* shell = Shell::Get();
   TabletModeControllerTestApi().EnterTabletMode();
   ASSERT_TRUE(shell->tablet_mode_controller()->InTabletMode());
@@ -6490,7 +6533,7 @@
 }
 
 // Tests the bar's visibility while entering or leaving overview mode.
-TEST_F(PersistentDesksBarTest, OverviewMode) {
+TEST_P(PersistentDesksBarTest, OverviewMode) {
   auto* desks_controller = DesksController::Get();
   ASSERT_EQ(1u, desks_controller->desks().size());
 
@@ -6555,7 +6598,7 @@
 }
 
 // Tests the desk activation changes after clicking the desk button in the bar.
-TEST_F(PersistentDesksBarTest, DeskActivation) {
+TEST_P(PersistentDesksBarTest, DeskActivation) {
   auto* desks_controller = DesksController::Get();
   auto* event_generator = GetEventGenerator();
 
@@ -6586,7 +6629,7 @@
   }
 }
 
-TEST_F(PersistentDesksBarTest, LeavingOrEnteringTabletModeWithOverviewModeOn) {
+TEST_P(PersistentDesksBarTest, LeavingOrEnteringTabletModeWithOverviewModeOn) {
   NewDesk();
   EXPECT_EQ(2u, DesksController::Get()->desks().size());
   EXPECT_TRUE(GetBarWidget());
@@ -6605,7 +6648,7 @@
 
 // Tests that the bar can be shown or hidden correctly through the context menu
 // of the bar.
-TEST_F(PersistentDesksBarTest, ShowOrHideBarThroughContextMenu) {
+TEST_P(PersistentDesksBarTest, ShowOrHideBarThroughContextMenu) {
   NewDesk();
   EXPECT_EQ(2u, DesksController::Get()->desks().size());
   EXPECT_TRUE(GetBarWidget());
@@ -6640,7 +6683,7 @@
 
 // Tests that the bar will only be created and shown when the shelf is
 // bottom-aligned.
-TEST_F(PersistentDesksBarTest, BentoBarWithShelfAlignment) {
+TEST_P(PersistentDesksBarTest, BentoBarWithShelfAlignment) {
   Shelf* shelf = Shelf::ForWindow(Shell::GetPrimaryRootWindow());
 
   // Create a new desk should cause the bar to be created and shown.
@@ -6672,7 +6715,7 @@
 }
 
 // Tests that the bar is not affected by the launcher opening.
-TEST_F(PersistentDesksBarTest, BarStaysOpenWhenLauncherOpens) {
+TEST_P(PersistentDesksBarTest, BarStaysOpenWhenLauncherOpens) {
   AppListControllerImpl* app_list_controller =
       Shell::Get()->app_list_controller();
 
@@ -6694,7 +6737,7 @@
 }
 
 // Tests that the bar will not be created if Docked Magnifier is on.
-TEST_F(PersistentDesksBarTest, NoPersistentDesksBarWithDockedMagnifierOn) {
+TEST_P(PersistentDesksBarTest, NoPersistentDesksBarWithDockedMagnifierOn) {
   AccessibilityControllerImpl* accessibility_controller =
       Shell::Get()->accessibility_controller();
 
@@ -6723,7 +6766,7 @@
 }
 
 // Tests that the bar will not be created if ChromeVox is on.
-TEST_F(PersistentDesksBarTest, NoPersistentDesksBarWithChromeVoxOn) {
+TEST_P(PersistentDesksBarTest, NoPersistentDesksBarWithChromeVoxOn) {
   AccessibilityControllerImpl* accessibility_controller =
       Shell::Get()->accessibility_controller();
 
@@ -6752,7 +6795,7 @@
 }
 
 // Tests that the bar will not be created if any window is fullscreened.
-TEST_F(PersistentDesksBarTest, NoPersistentDesksBarWithFullscreenedWindow) {
+TEST_P(PersistentDesksBarTest, NoPersistentDesksBarWithFullscreenedWindow) {
   // Create a secondary display.
   UpdateDisplay("400x300,500x400");
   WMEvent event_toggle_fullscreen(WM_EVENT_TOGGLE_FULLSCREEN);
@@ -6827,7 +6870,7 @@
 }
 
 // Tests that the bar should not be created in non-active user session.
-TEST_F(PersistentDesksBarTest, NoPersistentDesksBarInNonActiveUserSession) {
+TEST_P(PersistentDesksBarTest, NoPersistentDesksBarInNonActiveUserSession) {
   AccessibilityControllerImpl* accessibility_controller =
       Shell::Get()->accessibility_controller();
   TestSessionControllerClient* client = GetSessionControllerClient();
@@ -6852,7 +6895,7 @@
   EXPECT_TRUE(IsWidgetVisible());
 }
 
-TEST_F(PersistentDesksBarTest, DisplayMetricsChanged) {
+TEST_P(PersistentDesksBarTest, DisplayMetricsChanged) {
   UpdateDisplay("800x600,400x500");
   NewDesk();
   EXPECT_TRUE(GetBarWidget());
@@ -6902,7 +6945,7 @@
 
 // Tests bento bar's state on the pref `kBentoBarEnabled` changes. And its value
 // should be independent among users.
-TEST_F(PersistentDesksBarTest, UpdateBarStateOnPrefChanges) {
+TEST_P(PersistentDesksBarTest, UpdateBarStateOnPrefChanges) {
   const char kUser1[] = "user1@test.com";
   const char kUser2[] = "user2@test.com";
   const AccountId kUserAccount1 = AccountId::FromUserEmail(kUser1);
@@ -6950,7 +6993,7 @@
 
 // Tests desks bar's position in overview and app window's position in
 // split view.
-TEST_F(PersistentDesksBarTest, SnappingWindowsInOverview) {
+TEST_P(PersistentDesksBarTest, SnappingWindowsInOverview) {
   UpdateDisplay("800x600");
   NewDesk();
   std::unique_ptr<aura::Window> window1 =
@@ -7005,7 +7048,7 @@
 
 // Tests that dragging and dropping window to new desk while desks bar view is
 // at zero state.
-TEST_F(DragWindowToNewDeskTest, DragWindowAtZeroState) {
+TEST_P(DragWindowToNewDeskTest, DragWindowAtZeroState) {
   auto* controller = DesksController::Get();
   auto win1 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
 
@@ -7079,7 +7122,7 @@
 // close enough to the new desk button, desks bar should be transformed to
 // expanded state. In the end, if the window is not dropped on the new desk,
 // desk bar will be transformed back to zero state once the drag is completed.
-TEST_F(DragWindowToNewDeskTest,
+TEST_P(DragWindowToNewDeskTest,
        DragWindowAtZeroStateWithoutDroppingItOnTheNewDesk) {
   auto* controller = DesksController::Get();
   auto win1 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
@@ -7137,7 +7180,7 @@
 
 // Tests that dragging and dropping window to new desk while desks bar view is
 // at expanded state.
-TEST_F(DragWindowToNewDeskTest, DragWindowAtExpandedState) {
+TEST_P(DragWindowToNewDeskTest, DragWindowAtExpandedState) {
   auto* controller = DesksController::Get();
   auto win1 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
   NewDesk();
@@ -7170,15 +7213,20 @@
   EXPECT_TRUE(base::Contains(controller->desks()[2]->windows(), win1.get()));
 }
 
-// Tests that dragging and dropping window to new desk while the number of desks
-// has already reached to the maximum number 8.
-TEST_F(DragWindowToNewDeskTest, DragWindowAtMaximumDesksState) {
+// Tests that dragging and dropping a window on the new desk button does not
+// create a new desk if we are already at the maximum number of desks.
+TEST_P(DragWindowToNewDeskTest, DragWindowAtMaximumDesksState) {
+  // Set a display mode that forces vertical layout of split view drag
+  // indicators. This is so that we are able to drop an overview item on the
+  // "new desk" button even if it's right up to the edge.
+  UpdateDisplay("800x801");
+
   auto* controller = DesksController::Get();
   auto win1 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
-  while (controller->desks().size() < desks_util::kMaxNumberOfDesks)
+  while (controller->desks().size() < desks_util::GetMaxNumberOfDesks())
     NewDesk();
 
-  ASSERT_EQ(desks_util::kMaxNumberOfDesks, controller->desks().size());
+  ASSERT_EQ(desks_util::GetMaxNumberOfDesks(), controller->desks().size());
   auto* overview_controller = Shell::Get()->overview_controller();
   EnterOverview();
 
@@ -7187,21 +7235,41 @@
       GetOverviewGridForRoot(Shell::GetPrimaryRootWindow())->desks_bar_view();
   ASSERT_TRUE(desks_bar_view);
 
-  // Drag and drop |overview_item1| to |expanded_state_new_desk_button|. Since
-  // we already have maximum number of desks, this won't create a new desk, and
-  // the dragged window will fall back to the desk where it's from.
-  DragItemToPoint(
-      overview_controller->overview_session()->GetOverviewItemForWindow(
-          win1.get()),
-      desks_bar_view->expanded_state_new_desk_button()
-          ->GetBoundsInScreen()
-          .CenterPoint(),
-      GetEventGenerator());
+  auto* event_generator = GetEventGenerator();
+  auto* scroll_right_button = DesksTestApi::GetDesksBarRightScrollButton();
+  for (int i = 0; i != 3; ++i)
+    ClickOnView(scroll_right_button, event_generator);
 
-  // We should still have the max number of desks. And |win1| should still
-  // belong to the first desk.
-  EXPECT_EQ(desks_util::kMaxNumberOfDesks, desks_bar_view->mini_views().size());
-  EXPECT_EQ(desks_util::kMaxNumberOfDesks, controller->desks().size());
+  // Drag and drop the overview to the new desk button. Since we already have
+  // maximum number of desks, this won't create a new desk, and the dragged
+  // window will fall back to the desk where it's from. Dragging here is not
+  // done using `DragItemToPoint`. This is because once a drag has been
+  // initiated, the split view drag indicators will show and shift the position
+  // of the desks bar, which includes the new desk button. In other words, we
+  // have to initiate the drag before we can know where to drop.
+  const gfx::Point overview_item_center =
+      gfx::ToRoundedPoint(overview_controller->overview_session()
+                              ->GetOverviewItemForWindow(win1.get())
+                              ->target_bounds()
+                              .CenterPoint());
+
+  // Pick up the item and move it a little bit to initiate a drag.
+  event_generator->set_current_screen_location(overview_item_center);
+  event_generator->PressLeftButton();
+  event_generator->MoveMouseBy(20, 0);
+
+  // Move the item to the new desk button and drop it.
+  event_generator->MoveMouseTo(desks_bar_view->expanded_state_new_desk_button()
+                                   ->GetBoundsInScreen()
+                                   .CenterPoint());
+  event_generator->ReleaseLeftButton();
+
+  // We should still be in overview mode. We should still have the max number of
+  // desks. And `win1` should still belong to the first desk.
+  ASSERT_TRUE(overview_controller->InOverviewSession());
+  EXPECT_EQ(desks_util::GetMaxNumberOfDesks(),
+            desks_bar_view->mini_views().size());
+  EXPECT_EQ(desks_util::GetMaxNumberOfDesks(), controller->desks().size());
   EXPECT_TRUE(base::Contains(controller->desks()[0]->windows(), win1.get()));
 }
 
@@ -7313,7 +7381,7 @@
 
 // Runs through test cases for closing active and inactive desks with windows in
 // overview.
-TEST_F(DesksCloseAllTest, CloseDesksWithWindowsInOverview) {
+TEST_P(DesksCloseAllTest, CloseDesksWithWindowsInOverview) {
   // Possible sources for "close all" actions. `kCloseAllButton` means that we
   // will be trying to close the desk through the designated button on the
   // desk's `DeskActionView`, while `kContextMenu` means we will be trying to
@@ -7412,7 +7480,7 @@
 }
 
 // Test that a stored desk is cleared when we add a desk.
-TEST_F(DesksCloseAllTest, ClearStoredDeskWhenDeskAdded) {
+TEST_P(DesksCloseAllTest, ClearStoredDeskWhenDeskAdded) {
   // Create two desks with one app window each.
   WindowHolder win1(CreateAppWindow());
   WindowHolder win2(CreateAppWindow());
@@ -7446,7 +7514,7 @@
 // should replace the first desk in storage. If the second desk is being removed
 // by a combine desks operation or an immediate close-all operation, then the
 // stored desk should be cleared.
-TEST_F(DesksCloseAllTest, ClearStoredDeskWhenClosingAnotherDesk) {
+TEST_P(DesksCloseAllTest, ClearStoredDeskWhenClosingAnotherDesk) {
   // These test cases are differentiated on whether they use the
   // close-all-and-wait operation to remove the second desk (where
   // `desk_close_type` is `DeskCloseType::kCloseAllWindowsAndWait`), if they
@@ -7522,7 +7590,7 @@
 // original position and its original active state when the undo callback is
 // run. Also tests that a desk is destroyed when we allow for the undo toast to
 // expire.
-TEST_F(DesksCloseAllTest, RestoreOrDestroyDeskWithToast) {
+TEST_P(DesksCloseAllTest, RestoreOrDestroyDeskWithToast) {
   // These test cases are differentiated by whether they run the undo toast's
   // callback to restore the desk (when `restore_desk` is true) or if they let
   // the undo toast expire and destroy the removed desk (when `restore_desk` is
@@ -7588,7 +7656,7 @@
 // Checks that the combine desks button and context menu option are not visible
 // when there are no windows on a desk, and that they are visible on desks with
 // windows.
-TEST_F(DesksCloseAllTest, HideCombineDesksOptionWhenNoWindowsOnDesk) {
+TEST_P(DesksCloseAllTest, HideCombineDesksOptionWhenNoWindowsOnDesk) {
   // Create a new desk with no windows to have an expanded desks bar view with
   // mini views.
   NewDesk();
@@ -7635,7 +7703,7 @@
 
 // Tests that the shortcut to close all (Ctrl + Shift + W) on a desk mini view
 // works as expected.
-TEST_F(DesksCloseAllTest, ShortcutCloseAll) {
+TEST_P(DesksCloseAllTest, ShortcutCloseAll) {
   WindowHolder window1(CreateAppWindow());
   WindowHolder window2(CreateAppWindow());
   NewDesk();
@@ -7672,7 +7740,7 @@
   EXPECT_FALSE(window2.is_valid());
 }
 
-TEST_F(DesksCloseAllTest, ShortcutUndoCloseAll) {
+TEST_P(DesksCloseAllTest, ShortcutUndoCloseAll) {
   WindowHolder window1(CreateAppWindow());
   WindowHolder window2(CreateAppWindow());
   NewDesk();
@@ -7701,7 +7769,7 @@
 }
 
 // Tests CloseAll on active desk will close app windows on it.
-TEST_F(DesksCloseAllTest, CloseActiveDeskCloseWindows) {
+TEST_P(DesksCloseAllTest, CloseActiveDeskCloseWindows) {
   WindowHolder window1(CreateAppWindow());
   WindowHolder window2(CreateAppWindow());
 
@@ -7727,7 +7795,7 @@
 }
 
 // Tests CloseAll will forcefully close window that is not closed in time.
-TEST_F(DesksCloseAllTest, ForceCloseWindows) {
+TEST_P(DesksCloseAllTest, ForceCloseWindows) {
   WindowHolder window1(CreateAppWindow());
 
   WindowHolder window2(CreateAppWindow(gfx::Rect(), AppType::SYSTEM_APP,
@@ -7761,7 +7829,7 @@
 // Checks that the desk preview highlight overlay is visible on a desk preview
 // view only when its corresponding desk mini view's `DeskActionContextMenu` is
 // active.
-TEST_F(DesksCloseAllTest, DeskPreviewHighlightShowsWhenContextMenuIsOpen) {
+TEST_P(DesksCloseAllTest, DeskPreviewHighlightShowsWhenContextMenuIsOpen) {
   // We need to make the display this large so that the preview view is
   // right-clickable.
   UpdateDisplay("1366x768");
@@ -7799,7 +7867,7 @@
 
 // Checks that the combine desks tooltip's validity is maintained whenever the
 // user adds a desk, closes a desk, moves a desk, or changes the name of a desk.
-TEST_F(DesksCloseAllTest, CombineDesksTooltipIsUpdatedOnUserActions) {
+TEST_P(DesksCloseAllTest, CombineDesksTooltipIsUpdatedOnUserActions) {
   // Possible sources for tooltip updates.
   enum class UpdateSource {
     kAddDesk,
@@ -7932,7 +8000,7 @@
   }
 }
 // Test metrics are being recorded in close all case.
-TEST_F(DesksCloseAllTest, TestMetricsRecordingWhenCloseAllWindows) {
+TEST_P(DesksCloseAllTest, TestMetricsRecordingWhenCloseAllWindows) {
   struct {
     const std::string scope_trace;
     const bool restore_desk;
@@ -8003,7 +8071,7 @@
 
 // Checks that a `DeskActionContextMenu` opens when the user long-presses a
 // desk's mini view.
-TEST_F(DesksCloseAllTest, ContextMenuOpensOnLongPress) {
+TEST_P(DesksCloseAllTest, ContextMenuOpensOnLongPress) {
   NewDesk();
   EnterOverview();
   ASSERT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
@@ -8021,7 +8089,7 @@
 
 // Tests that desks can be closed in quick succession while still saving the
 // removed desk.
-TEST_F(DesksCloseAllTest, CanCloseMultipleDesksInSuccessionAndUndo) {
+TEST_P(DesksCloseAllTest, CanCloseMultipleDesksInSuccessionAndUndo) {
   NewDesk();
   NewDesk();
   auto* controller = DesksController::Get();
@@ -8040,7 +8108,7 @@
 
 // Tests that an active desk's windows are restored with an identity transform
 // when it's removal is undone outside of overview mode.
-TEST_F(DesksCloseAllTest,
+TEST_P(DesksCloseAllTest,
        ActiveDeskWindowsAreRestoredProperlyOutsideOfOverview) {
   WindowHolder window(CreateAppWindow());
   NewDesk();
@@ -8078,7 +8146,7 @@
 
 // Tests that we can undo close-all solely via keyboard navigation (tabbing to
 // the undo toast and pressing enter).
-TEST_F(DesksCloseAllTest, CanUndoDeskClosureThroughKeyboardNavigation) {
+TEST_P(DesksCloseAllTest, CanUndoDeskClosureThroughKeyboardNavigation) {
   NewDesk();
   Shell::Get()->accessibility_controller()->spoken_feedback().SetEnabled(true);
   EnterOverview();
@@ -8115,16 +8183,16 @@
 
 // Tests that we can create the maximum number of desks, remove one, and add one
 // before the toast asking if the user would like to undo goes away.
-TEST_F(DesksCloseAllTest, CanAddLastDeskWhileUndoToastIsBeingDisplayed) {
+TEST_P(DesksCloseAllTest, CanAddLastDeskWhileUndoToastIsBeingDisplayed) {
   auto* controller = DesksController::Get();
-  while (controller->desks().size() < desks_util::kMaxNumberOfDesks)
+  while (controller->desks().size() < desks_util::GetMaxNumberOfDesks())
     NewDesk();
-  ASSERT_EQ(desks_util::kMaxNumberOfDesks, controller->desks().size());
+  ASSERT_EQ(desks_util::GetMaxNumberOfDesks(), controller->desks().size());
 
   // Create a window to ensure that closing windows after removing the last desk
   // still occurs correctly.
   WindowHolder window(CreateAppWindow());
-  const int last_desk_index = desks_util::kMaxNumberOfDesks - 1;
+  const int last_desk_index = desks_util::GetMaxNumberOfDesks() - 1;
   controller->SendToDeskAtIndex(window.window(), last_desk_index);
 
   EnterOverview();
@@ -8133,7 +8201,7 @@
   // Remove the last desk with close-all. This should show the undo toast.
   RemoveDesk(controller->desks()[last_desk_index].get(),
              DeskCloseType::kCloseAllWindowsAndWait);
-  ASSERT_EQ(desks_util::kMaxNumberOfDesks - 1, controller->desks().size());
+  ASSERT_EQ(desks_util::GetMaxNumberOfDesks() - 1, controller->desks().size());
   ASSERT_TRUE(DesksTestApi::DesksControllerCanUndoDeskRemoval());
 
   // The new desk button should be enabled at this point.
@@ -8142,11 +8210,16 @@
                               ->inner_button();
   ASSERT_TRUE(new_desk_button->GetEnabled());
 
+  // Scroll all the way to the right to ensure that the new button is visible.
+  auto* event_generator = GetEventGenerator();
+  auto* scroll_right_button = DesksTestApi::GetDesksBarRightScrollButton();
+  for (int i = 0; i != 3; ++i)
+    ClickOnView(scroll_right_button, event_generator);
+
   // If we click on the `new_desk_button`, we should create a new desk and
   // destroy the previously removed desk and the window inside of it.
-  auto* event_generator = GetEventGenerator();
   ClickOnView(new_desk_button, event_generator);
-  EXPECT_EQ(desks_util::kMaxNumberOfDesks, controller->desks().size());
+  EXPECT_EQ(desks_util::GetMaxNumberOfDesks(), controller->desks().size());
   EXPECT_FALSE(DesksTestApi::DesksControllerCanUndoDeskRemoval());
 
   // Ensure that the window is still closed properly.
@@ -8160,7 +8233,35 @@
 // - Reusing containers when desks are removed and created.
 
 // Instantiate the parametrized tests.
-INSTANTIATE_TEST_SUITE_P(All, DesksTest, ::testing::Bool());
+
+// This is used for tests that test all combinations of 8/16 desks as well as
+// clicks/touch.
+constexpr DesksTestParams kAllCombinations[] = {
+    {.use_touch_gestures = false, .use_16_desks = false},
+    {.use_touch_gestures = false, .use_16_desks = true},
+    {.use_touch_gestures = true, .use_16_desks = false},
+    {.use_touch_gestures = true, .use_16_desks = true},
+};
+
+// This is used for tests that only want to test 8/16 desks.
+constexpr DesksTestParams kDeskCountOnly[] = {
+    {.use_16_desks = false},
+    {.use_16_desks = true},
+};
+
+INSTANTIATE_TEST_SUITE_P(All, DesksTest, ValuesIn(kAllCombinations));
+
+INSTANTIATE_TEST_SUITE_P(All, DesksEditableNamesTest, ValuesIn(kDeskCountOnly));
+INSTANTIATE_TEST_SUITE_P(All, TabletModeDesksTest, ValuesIn(kDeskCountOnly));
+INSTANTIATE_TEST_SUITE_P(All, DesksAcceleratorsTest, ValuesIn(kDeskCountOnly));
+INSTANTIATE_TEST_SUITE_P(All, DesksBentoBarTest, ValuesIn(kDeskCountOnly));
+INSTANTIATE_TEST_SUITE_P(All, DesksMockTimeTest, ValuesIn(kDeskCountOnly));
+INSTANTIATE_TEST_SUITE_P(All, PersistentDesksBarTest, ValuesIn(kDeskCountOnly));
+INSTANTIATE_TEST_SUITE_P(All,
+                         DragWindowToNewDeskTest,
+                         ValuesIn(kDeskCountOnly));
+INSTANTIATE_TEST_SUITE_P(All, DesksCloseAllTest, ValuesIn(kDeskCountOnly));
+
 INSTANTIATE_TEST_SUITE_P(All, PerDeskShelfTest, ::testing::Bool());
 
 }  // namespace
diff --git a/ash/wm/desks/desks_util.cc b/ash/wm/desks/desks_util.cc
index 92d7ce2..125b9ffa 100644
--- a/ash/wm/desks/desks_util.cc
+++ b/ash/wm/desks/desks_util.cc
@@ -6,6 +6,7 @@
 
 #include <array>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/tablet_mode.h"
 #include "ash/shell.h"
 #include "ash/wm/desks/desk.h"
@@ -25,7 +26,7 @@
 
 namespace {
 
-constexpr std::array<int, kMaxNumberOfDesks> kDesksContainersIds = {
+constexpr std::array<int, kDesksUpperLimit> kDesksContainersIds = {
     kShellWindowId_DefaultContainerDeprecated,
     kShellWindowId_DeskContainerB,
     kShellWindowId_DeskContainerC,
@@ -34,13 +35,28 @@
     kShellWindowId_DeskContainerF,
     kShellWindowId_DeskContainerG,
     kShellWindowId_DeskContainerH,
+    kShellWindowId_DeskContainerI,
+    kShellWindowId_DeskContainerJ,
+    kShellWindowId_DeskContainerK,
+    kShellWindowId_DeskContainerL,
+    kShellWindowId_DeskContainerM,
+    kShellWindowId_DeskContainerN,
+    kShellWindowId_DeskContainerO,
+    kShellWindowId_DeskContainerP,
 };
 
+// Default max number of desks (that is, enable-16-desks is off).
+constexpr size_t kDesksDefaultLimit = 8;
+
 }  // namespace
 
+size_t GetMaxNumberOfDesks() {
+  return features::Is16DesksEnabled() ? kDesksUpperLimit : kDesksDefaultLimit;
+}
+
 std::vector<int> GetDesksContainersIds() {
   return std::vector<int>(kDesksContainersIds.begin(),
-                          kDesksContainersIds.end());
+                          kDesksContainersIds.begin() + GetMaxNumberOfDesks());
 }
 
 std::vector<aura::Window*> GetDesksContainers(aura::Window* root) {
@@ -85,6 +101,30 @@
     case kShellWindowId_DeskContainerH:
       return "Desk_Container_H";
 
+    case kShellWindowId_DeskContainerI:
+      return "Desk_Container_I";
+
+    case kShellWindowId_DeskContainerJ:
+      return "Desk_Container_J";
+
+    case kShellWindowId_DeskContainerK:
+      return "Desk_Container_K";
+
+    case kShellWindowId_DeskContainerL:
+      return "Desk_Container_L";
+
+    case kShellWindowId_DeskContainerM:
+      return "Desk_Container_M";
+
+    case kShellWindowId_DeskContainerN:
+      return "Desk_Container_N";
+
+    case kShellWindowId_DeskContainerO:
+      return "Desk_Container_O";
+
+    case kShellWindowId_DeskContainerP:
+      return "Desk_Container_P";
+
     default:
       NOTREACHED();
       return "";
@@ -104,7 +144,15 @@
          id == kShellWindowId_DeskContainerE ||
          id == kShellWindowId_DeskContainerF ||
          id == kShellWindowId_DeskContainerG ||
-         id == kShellWindowId_DeskContainerH;
+         id == kShellWindowId_DeskContainerH ||
+         id == kShellWindowId_DeskContainerI ||
+         id == kShellWindowId_DeskContainerJ ||
+         id == kShellWindowId_DeskContainerK ||
+         id == kShellWindowId_DeskContainerL ||
+         id == kShellWindowId_DeskContainerM ||
+         id == kShellWindowId_DeskContainerN ||
+         id == kShellWindowId_DeskContainerO ||
+         id == kShellWindowId_DeskContainerP;
 }
 
 int GetActiveDeskContainerId() {
diff --git a/ash/wm/desks/desks_util.h b/ash/wm/desks/desks_util.h
index 7715c91..c6d1f5a 100644
--- a/ash/wm/desks/desks_util.h
+++ b/ash/wm/desks/desks_util.h
@@ -25,7 +25,12 @@
 
 namespace desks_util {
 
-constexpr size_t kMaxNumberOfDesks = 8;
+// Note: the max number of desks depends on a runtime flag and the function
+// `GetMaxNumberOfDesks` below will return that value. The value returned from
+// that function will not be more than this constant.
+constexpr size_t kDesksUpperLimit = 16;
+
+ASH_EXPORT size_t GetMaxNumberOfDesks();
 
 ASH_EXPORT std::vector<int> GetDesksContainersIds();
 
diff --git a/ash/wm/desks/root_window_desk_switch_animator.cc b/ash/wm/desks/root_window_desk_switch_animator.cc
index 1509c836..8d27812c 100644
--- a/ash/wm/desks/root_window_desk_switch_animator.cc
+++ b/ash/wm/desks/root_window_desk_switch_animator.cc
@@ -120,7 +120,7 @@
   DCHECK_NE(starting_desk_index_, ending_desk_index_);
   DCHECK(delegate_);
 
-  screenshot_layers_.resize(desks_util::kMaxNumberOfDesks);
+  screenshot_layers_.resize(desks_util::GetMaxNumberOfDesks());
 }
 
 RootWindowDeskSwitchAnimator::~RootWindowDeskSwitchAnimator() {
diff --git a/ash/wm/desks/templates/saved_desk_presenter.cc b/ash/wm/desks/templates/saved_desk_presenter.cc
index 5d50272..1e1dff08 100644
--- a/ash/wm/desks/templates/saved_desk_presenter.cc
+++ b/ash/wm/desks/templates/saved_desk_presenter.cc
@@ -409,7 +409,7 @@
         /*text=*/
         l10n_util::GetStringFUTF16(
             IDS_ASH_DESKS_TEMPLATES_REACH_MAXIMUM_DESK_TOAST,
-            base::FormatNumber(desks_util::kMaxNumberOfDesks))};
+            base::FormatNumber(desks_util::GetMaxNumberOfDesks()))};
     ToastManager::Get()->Show(toast_data);
     return;
   }
diff --git a/ash/wm/desks/templates/saved_desk_unittest.cc b/ash/wm/desks/templates/saved_desk_unittest.cc
index 7f245a02..cc3ebb5 100644
--- a/ash/wm/desks/templates/saved_desk_unittest.cc
+++ b/ash/wm/desks/templates/saved_desk_unittest.cc
@@ -4408,6 +4408,50 @@
   ASSERT_FALSE(InOverviewSession());
 }
 
+// Tests that adding desks to the max and then saving and recalling one of the
+// desks successfully disables the new desk button.
+TEST_F(DeskSaveAndRecallTest, NewDeskButtonDisabledWhenRecallingToMaxDesks) {
+  auto* controller = DesksController::Get();
+
+  while (controller->CanCreateDesks())
+    NewDesk();
+
+  // Activate the last desk and add a window in it that will be destroyed later.
+  ActivateDesk(controller->desks().back().get());
+  aura::WindowTracker tracker({CreateAppWindow().release()});
+  ToggleOverview();
+  ASSERT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
+
+  // We should have the max number of desks at this point and therefore the new
+  // desk button should be disabled.
+  auto* new_desk_button = GetPrimaryRootDesksBarView()
+                              ->expanded_state_new_desk_button()
+                              ->inner_button();
+  ASSERT_FALSE(controller->CanCreateDesks());
+  ASSERT_FALSE(new_desk_button->GetEnabled());
+
+  // After saving the last desk for later, the new desk button should be enabled
+  // again.
+  auto* root = Shell::GetPrimaryRootWindow();
+  ASSERT_TRUE(GetOverviewGridForRoot(root)->IsSaveDeskForLaterButtonVisible());
+  ClickOnView(GetSaveDeskForLaterButtonForRoot(root));
+  WaitForDesksTemplatesUI();
+  WaitForDesksTemplatesUI();
+  ASSERT_TRUE(controller->CanCreateDesks());
+  ASSERT_TRUE(new_desk_button->GetEnabled());
+
+  // Press return so that we can open the saved desk next.
+  SendKey(ui::VKEY_RETURN);
+
+  // Recall the desk. This should disable the new desk button again.
+  SavedDeskItemView* template_item =
+      GetItemViewFromTemplatesGrid(/*grid_item_index=*/0);
+  ASSERT_TRUE(template_item);
+  ClickOnView(template_item);
+  ASSERT_FALSE(controller->CanCreateDesks());
+  EXPECT_FALSE(new_desk_button->GetEnabled());
+}
+
 // Tests that we can not save an empty desk as a template. Regression test for
 // https://crbug.com/1351520.
 TEST_F(SavedDeskTest, NoEmptyDeskTemplate) {
diff --git a/ash/wm/overview/overview_highlight_controller_unittest.cc b/ash/wm/overview/overview_highlight_controller_unittest.cc
index 39fd7d2..46f282e 100644
--- a/ash/wm/overview/overview_highlight_controller_unittest.cc
+++ b/ash/wm/overview/overview_highlight_controller_unittest.cc
@@ -884,7 +884,8 @@
     SendKey(ui::VKEY_TAB);
   }
   EXPECT_FALSE(new_desk_button->GetEnabled());
-  EXPECT_EQ(desks_util::kMaxNumberOfDesks, desks_controller->desks().size());
+  EXPECT_EQ(desks_util::GetMaxNumberOfDesks(),
+            desks_controller->desks().size());
 }
 
 TEST_P(DesksOverviewHighlightControllerTest, ZeroStateOfDesksBar) {
diff --git a/ash/wm/window_cycle/window_cycle_controller.cc b/ash/wm/window_cycle/window_cycle_controller.cc
index 4abaf8c..c3cad759 100644
--- a/ash/wm/window_cycle/window_cycle_controller.cc
+++ b/ash/wm/window_cycle/window_cycle_controller.cc
@@ -92,7 +92,7 @@
                active_desk_container_id_before_cycle);
   base::UmaHistogramExactLinear(kAltTabDesksSwitchDistanceHistogramName,
                                 desks_switch_distance,
-                                desks_util::kMaxNumberOfDesks);
+                                desks_util::kDesksUpperLimit);
 }
 
 }  // namespace
diff --git a/ash/wm/window_restore/window_restore_controller.cc b/ash/wm/window_restore/window_restore_controller.cc
index 9745c4af..7737753 100644
--- a/ash/wm/window_restore/window_restore_controller.cc
+++ b/ash/wm/window_restore/window_restore_controller.cc
@@ -49,7 +49,7 @@
 WindowRestoreController::SaveWindowCallback g_save_window_callback_for_testing;
 
 // The list of possible app window parents.
-constexpr ShellWindowId kAppParentContainers[11] = {
+constexpr ShellWindowId kAppParentContainers[19] = {
     kShellWindowId_DefaultContainerDeprecated,
     kShellWindowId_DeskContainerB,
     kShellWindowId_DeskContainerC,
@@ -58,6 +58,14 @@
     kShellWindowId_DeskContainerF,
     kShellWindowId_DeskContainerG,
     kShellWindowId_DeskContainerH,
+    kShellWindowId_DeskContainerI,
+    kShellWindowId_DeskContainerJ,
+    kShellWindowId_DeskContainerK,
+    kShellWindowId_DeskContainerL,
+    kShellWindowId_DeskContainerM,
+    kShellWindowId_DeskContainerN,
+    kShellWindowId_DeskContainerO,
+    kShellWindowId_DeskContainerP,
     kShellWindowId_AlwaysOnTopContainer,
     kShellWindowId_FloatContainer,
     kShellWindowId_UnparentedContainer,
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 5922a2f..799f5f42 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -31,6 +31,7 @@
 import("//build/config/nacl/config.gni")
 import("//build/config/profiling/profiling.gni")
 import("//build/config/rust.gni")
+import("//build/config/sanitizers/sanitizers.gni")
 import("//build/config/sysroot.gni")
 import("//build/config/ui.gni")
 import("//build/nocompile.gni")
@@ -2634,7 +2635,10 @@
   header = "sanitizer_buildflags.h"
   header_dir = "base"
 
-  flags = [ "IS_HWASAN=$is_hwasan" ]
+  flags = [
+    "IS_HWASAN=$is_hwasan",
+    "USING_SANITIZER=$using_sanitizer",
+  ]
 }
 
 buildflag_header("tracing_buildflags") {
diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py
index 94776c0..6f3e4321 100755
--- a/base/android/jni_generator/jni_generator.py
+++ b/base/android/jni_generator/jni_generator.py
@@ -1553,18 +1553,18 @@
   return os.sep.join(script_components[base_index:])
 
 
-def _RemoveStaleHeaders(path, output_files):
+def _RemoveStaleHeaders(path, output_names):
   if not os.path.isdir(path):
     return
   # Do not remove output files so that timestamps on declared outputs are not
   # modified unless their contents are changed (avoids reverse deps needing to
   # be rebuilt).
-  preserve = set(output_files)
+  preserve = set(output_names)
   for root, _, files in os.walk(path):
     for f in files:
-      file_path = os.path.join(root, f)
-      if file_path not in preserve:
-        if os.path.isfile(file_path) and os.path.splitext(file_path)[1] == '.h':
+      if f not in preserve:
+        file_path = os.path.join(root, f)
+        if os.path.isfile(file_path) and file_path.endswith('.h'):
           os.remove(file_path)
 
 
@@ -1591,18 +1591,21 @@
       help='Uses as a namespace in the generated header '
       'instead of the javap class name, or when there is '
       'no JNINamespace annotation in the java source.')
-  parser.add_argument(
-      '--input_file',
-      action='append',
-      required=True,
-      dest='input_files',
-      help='Input file names, or paths within a .jar if '
-      '--jar-file is used.')
-  parser.add_argument(
-      '--output_file',
-      action='append',
-      dest='output_files',
-      help='Output file names.')
+  parser.add_argument('--input_file',
+                      action='append',
+                      required=True,
+                      dest='input_files',
+                      help='Input filenames, or paths within a .jar if '
+                      '--jar-file is used.')
+  parser.add_argument('--output_dir', required=True, help='Output directory.')
+  # TODO(agrieve): --prev_output_dir used only to make incremental builds work.
+  #     Remove --prev_output_dir at some point after 2022.
+  parser.add_argument('--prev_output_dir',
+                      help='Delete headers found in this directory.')
+  parser.add_argument('--output_name',
+                      action='append',
+                      dest='output_names',
+                      help='Output filenames within output directory.')
   parser.add_argument(
       '--script_name',
       default=GetScriptName(),
@@ -1651,22 +1654,28 @@
   parser.add_argument(
       '--split_name',
       help='Split name that the Java classes should be loaded from.')
+  # TODO(agrieve): --stamp used only to make incremental builds work.
+  #     Remove --stamp at some point after 2022.
+  parser.add_argument('--stamp',
+                      help='Process --prev_output_dir and touch this file.')
   args = parser.parse_args()
   input_files = args.input_files
-  output_files = args.output_files
-  if output_files:
-    output_dirs = set(os.path.dirname(f) for f in output_files)
-    if len(output_dirs) != 1:
-      parser.error(
-          'jni_generator only supports a single output directory per target '
-          '(got {})'.format(output_dirs))
-    output_dir = output_dirs.pop()
+  output_names = args.output_names
+
+  if args.prev_output_dir:
+    _RemoveStaleHeaders(args.prev_output_dir, [])
+
+  if args.stamp:
+    build_utils.Touch(args.stamp)
+    sys.exit(0)
+
+  if output_names:
     # Remove existing headers so that moving .java source files but not updating
     # the corresponding C++ include will be a compile failure (otherwise
     # incremental builds will usually not catch this).
-    _RemoveStaleHeaders(output_dir, output_files)
+    _RemoveStaleHeaders(args.output_dir, output_names)
   else:
-    output_files = [None] * len(input_files)
+    output_names = [None] * len(input_files)
   temp_dir = tempfile.mkdtemp()
   try:
     if args.jar_file:
@@ -1674,7 +1683,11 @@
         z.extractall(temp_dir, input_files)
       input_files = [os.path.join(temp_dir, f) for f in input_files]
 
-    for java_path, header_path in zip(input_files, output_files):
+    for java_path, header_name in zip(input_files, output_names):
+      if header_name:
+        header_path = os.path.join(args.output_dir, header_name)
+      else:
+        header_path = None
       GenerateJNIHeader(java_path, header_path, args)
   finally:
     shutil.rmtree(temp_dir)
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc
index 2b6624d..d746030 100644
--- a/base/metrics/field_trial.cc
+++ b/base/metrics/field_trial.cc
@@ -230,6 +230,18 @@
 
 FieldTrial::EntropyProvider::~EntropyProvider() = default;
 
+uint32_t FieldTrial::EntropyProvider::GetPseudorandomValue(
+    uint32_t salt,
+    uint32_t output_range) const {
+  // Passing a different salt is sufficient to get a "different" result from
+  // GetEntropyForTrial (ignoring collisions).
+  double entropy_value = GetEntropyForTrial(/*trial_name=*/"", salt);
+
+  // Convert the [0,1) double to an [0, output_range) integer.
+  return static_cast<uint32_t>(GetGroupBoundaryValue(
+      static_cast<FieldTrial::Probability>(output_range), entropy_value));
+}
+
 FieldTrial::PickleState::PickleState() = default;
 
 FieldTrial::PickleState::PickleState(const PickleState& other) = default;
diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h
index df231919..ef8e506dc 100644
--- a/base/metrics/field_trial.h
+++ b/base/metrics/field_trial.h
@@ -102,6 +102,10 @@
     // value given the same input |trial_name| and |randomization_seed| values.
     virtual double GetEntropyForTrial(StringPiece trial_name,
                                       uint32_t randomization_seed) const = 0;
+
+    // Returns a pseudorandom integer in [0, output_range).
+    // |salt| is a data parameter for the pseudorandom function.
+    uint32_t GetPseudorandomValue(uint32_t salt, uint32_t output_range) const;
   };
 
   // Separate type from FieldTrial::PickleState so that it can use StringPieces.
diff --git a/base/values.cc b/base/values.cc
index fc32dcc..b681b29 100644
--- a/base/values.cc
+++ b/base/values.cc
@@ -1805,11 +1805,6 @@
   list().emplace_back(std::move(in_list));
 }
 
-void ListValue::Swap(ListValue* other) {
-  CHECK(other->is_list());
-  list().swap(other->list());
-}
-
 ValueView::ValueView(const Value& value)
     : data_view_(
           value.Visit([](const auto& member) { return ViewType(member); })) {}
diff --git a/base/values.h b/base/values.h
index 65e7920..2ff78cd1 100644
--- a/base/values.h
+++ b/base/values.h
@@ -1410,11 +1410,6 @@
   void Append(base::Value::Dict in_dict);
   void Append(base::Value::List in_list);
 
-  // Swaps contents with the `other` list.
-  //
-  // DEPRECATED: prefer `base::Value::List` + `std::swap()`.
-  void Swap(ListValue* other);
-
   // Iteration: Use a range-based for loop over `base::Value::List` directly
   // instead.
 };
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py
index d93ee2f2..4c4a159 100755
--- a/build/android/gyp/write_build_config.py
+++ b/build/android/gyp/write_build_config.py
@@ -2035,6 +2035,18 @@
       secondary_abi_library_paths = _ExtractSharedLibsFromRuntimeDeps(
           options.secondary_abi_shared_libraries_runtime_deps)
       secondary_abi_library_paths.sort()
+      paths_without_parent_dirs = [
+          p for p in secondary_abi_library_paths if os.path.sep not in p
+      ]
+      if paths_without_parent_dirs:
+        sys.stderr.write('Found secondary native libraries from primary '
+                         'toolchain directory. This is a bug!\n')
+        sys.stderr.write('\n'.join(paths_without_parent_dirs))
+        sys.stderr.write('\n\nIt may be helpful to run: \n')
+        sys.stderr.write('    gn path out/Default //chrome/android:'
+                         'monochrome_secondary_abi_lib //base:base\n')
+        sys.exit(1)
+
       all_inputs.append(options.secondary_abi_shared_libraries_runtime_deps)
 
     native_library_placeholder_paths = build_utils.ParseGnList(
diff --git a/build/config/android/BUILD.gn b/build/config/android/BUILD.gn
index 11a9327..d00b883 100644
--- a/build/config/android/BUILD.gn
+++ b/build/config/android/BUILD.gn
@@ -2,7 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/config/android/config.gni")
+import("//build/config/android/rules.gni")
 import("//build/config/c++/c++.gni")
 import("//build/config/compiler/compiler.gni")
 import("//build/config/sanitizers/sanitizers.gni")
@@ -162,6 +162,10 @@
   }
 }
 
+config("jni_include_dir") {
+  include_dirs = [ jni_headers_dir ]
+}
+
 if (current_toolchain == default_toolchain) {
   pool("goma_javac_pool") {
     # Override action_pool when goma is enabled for javac.
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index 69d11b7..3552438 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -5,7 +5,6 @@
 # Do not add any imports to non-//build directories here.
 # Some projects (e.g. V8) do not have non-build directories DEPS'ed in.
 import("//build/config/android/config.gni")
-import("//build/config/android/copy_ex.gni")
 import("//build/config/compiler/compiler.gni")
 import("//build/config/compute_inputs_for_analyze.gni")
 import("//build/config/coverage/coverage.gni")
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 0136b04..05e634c 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -7,12 +7,13 @@
 
 import("//build/config/android/channel.gni")
 import("//build/config/android/config.gni")
-import("//build/config/android/internal_rules.gni")
+import("//build/config/android/copy_ex.gni")
 import("//build/config/clang/clang.gni")
 import("//build/config/compiler/compiler.gni")
 import("//build/config/coverage/coverage.gni")
 import("//build/config/python.gni")
 import("//build/config/rts.gni")
+import("//build/config/sanitizers/sanitizers.gni")
 import("//build/config/zip.gni")
 import("//build/toolchain/toolchain.gni")
 
@@ -22,6 +23,16 @@
   enable_jni_tracing = false
 }
 
+# Use a dedicated include dir so that files can #include headers from other
+# toolchains without affecting non-JNI #includes.
+if (target_os == "android") {
+  jni_headers_dir = "$root_build_dir/gen/jni_headers"
+} else {
+  # Chrome OS builds cannot share gen/ directories because is_android=false
+  # within default_toolchain.
+  jni_headers_dir = "$root_gen_dir/jni_headers"
+}
+
 if (target_cpu == "arm") {
   _sanitizer_arch = "arm"
 } else if (target_cpu == "arm64") {
@@ -124,11 +135,13 @@
 }
 
 if (enable_java_templates) {
-  import("//build/config/sanitizers/sanitizers.gni")
+  import("//build/config/android/internal_rules.gni")
 
   # JNI target implementation. See generate_jni or generate_jar_jni for usage.
   template("generate_jni_impl") {
-    _jni_output_dir = "${target_gen_dir}/${target_name}"
+    _prev_jni_output_dir = "$target_gen_dir/$target_name"
+    _subdir = rebase_path(target_gen_dir, root_gen_dir)
+    _jni_output_dir = "$jni_headers_dir/$_subdir/$target_name"
     if (defined(invoker.jni_generator_include)) {
       _jni_generator_include = invoker.jni_generator_include
       _jni_generator_include_deps = []
@@ -160,9 +173,18 @@
         public_deps = []
       }
       public_deps += _jni_generator_include_deps
+
+      public_configs = [ "//build/config/android:jni_include_dir" ]
       inputs = []
       args = [
         "--ptr_type=long",
+
+        # TODO(agrieve): --prev_output_dir used only to make incremental builds
+        #     work. Remove --prev_output_dir at some point after 2022.
+        "--prev_output_dir",
+        rebase_path(_prev_jni_output_dir, root_build_dir),
+        "--output_dir",
+        rebase_path(_jni_output_dir, root_build_dir),
         "--includes",
         rebase_path(_jni_generator_include, _jni_output_dir),
       ]
@@ -208,17 +230,16 @@
 
       outputs = []
       foreach(_name, _input_names) {
-        _name_part = get_path_info(_name, "name")
-        outputs += [ "${_jni_output_dir}/${_name_part}_jni.h" ]
-      }
+        _name = get_path_info(_name, "name") + "_jni.h"
+        outputs += [ "$_jni_output_dir/$_name" ]
 
-      # Avoid passing GN lists because not all webrtc embedders use //build.
-      foreach(_output, outputs) {
+        # Avoid passing GN lists because not all webrtc embedders use //build.
         args += [
-          "--output_file",
-          rebase_path(_output, root_build_dir),
+          "--output_name",
+          _name,
         ]
       }
+
       foreach(_input, _input_args) {
         args += [ "--input_file=$_input" ]
       }
@@ -229,6 +250,31 @@
       if (enable_jni_tracing) {
         args += [ "--enable_tracing" ]
       }
+      if (current_toolchain != default_toolchain && target_os == "android") {
+        # Rather than regenerating .h files in secondary toolchains, re-use the
+        # ones from the primary toolchain by depending on it and adding the
+        # root gen directory to the include paths.
+        # https://crbug.com/1369398
+        inputs = []
+        outputs = []
+        _stamp = "$target_gen_dir/$target_name.stamp"
+        outputs = [ _stamp ]
+
+        # Since we used to generate the .h files rather than delegate, the
+        # script will delete all .h files it finds in --prev_output_dir.
+        # TODO(agrieve): --prev_output_dir used only to make incremental builds
+        #     work. Convert to group() target at some point after 2022.
+        args += [
+          "--stamp",
+          rebase_path(_stamp, root_build_dir),
+        ]
+        deps = []
+        public_deps = []
+        public_deps = [ ":$target_name($default_toolchain)" ]
+      } else if (defined(visibility)) {
+        # Allow dependency on ourselves from secondary toolchain.
+        visibility += [ ":$target_name" ]
+      }
     }
   }
 
diff --git a/build/config/fuchsia/BUILD.gn b/build/config/fuchsia/BUILD.gn
index 2d9f205..55f837c 100644
--- a/build/config/fuchsia/BUILD.gn
+++ b/build/config/fuchsia/BUILD.gn
@@ -46,11 +46,21 @@
     "//third_party/fuchsia-sdk/sdk/tools/${test_host_cpu}/zbi",
     "//third_party/fuchsia-sdk/sdk/tools/${test_host_cpu}/zbi-meta.json",
   ]
-  if (test_isolate_uses_emulator) {
+
+  if (fuchsia_additional_boot_images == []) {
     data += [
       "${boot_image_root}/qemu/qemu-kernel.kernel",
       "${boot_image_root}/qemu/storage-full.blk",
       "${boot_image_root}/qemu/zircon-a.zbi",
+    ]
+  }
+
+  foreach(fuchsia_additional_boot_image, fuchsia_additional_boot_images) {
+    data += [ "${fuchsia_additional_boot_image}/" ]
+  }
+
+  if (test_isolate_uses_emulator) {
+    data += [
       "//third_party/fuchsia-sdk/sdk/bin/device_launcher.version",
       "//third_party/fuchsia-sdk/sdk/tools/${test_host_cpu}/fvdl",
     ]
@@ -71,9 +81,6 @@
       ]
     }
   }
-  foreach(fuchsia_additional_boot_image, fuchsia_additional_boot_images) {
-    data += [ "${fuchsia_additional_boot_image}/" ]
-  }
 }
 
 # Copy the loader to place it at the expected path in the final package.
diff --git a/build/linux/chrome.map b/build/linux/chrome.map
index c84a0ca..3038318 100644
--- a/build/linux/chrome.map
+++ b/build/linux/chrome.map
@@ -83,6 +83,13 @@
   localtime64_r;
   localtime_r;
 
+  # getaddrinfo() is exported by the sandbox to ensure the network service and
+  # other sandboxed processes don't try to run system DNS resolution
+  # in-process, which is not supported by the sandbox. This override
+  # uses dlsym(getaddrinfo) to make the real calls in unsandboxed
+  # processes.
+  getaddrinfo;
+
   v8dbg_*;
 
 local:
diff --git a/chrome/VERSION b/chrome/VERSION
index 46f355f..432e22f 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=108
 MINOR=0
-BUILD=5357
+BUILD=5358
 PATCH=0
diff --git a/chrome/android/expectations/monochrome_public_bundle__base.AndroidManifest.expected b/chrome/android/expectations/monochrome_public_bundle__base.AndroidManifest.expected
index 98318366..2d21cca 100644
--- a/chrome/android/expectations/monochrome_public_bundle__base.AndroidManifest.expected
+++ b/chrome/android/expectations/monochrome_public_bundle__base.AndroidManifest.expected
@@ -16,6 +16,7 @@
   </queries>  # DIFF-ANCHOR: 9588fea7
   <uses-feature android:glEsVersion="0x00020000"/>
   <uses-feature android:name="android.hardware.camera" android:required="false"/>
+  <uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
   <uses-feature android:name="android.hardware.location.gps" android:required="false"/>
   <uses-feature android:name="android.hardware.microphone" android:required="false"/>
   <uses-feature android:name="android.hardware.screen.landscape" android:required="false"/>
diff --git a/chrome/android/expectations/trichrome_chrome_bundle__base.AndroidManifest.expected b/chrome/android/expectations/trichrome_chrome_bundle__base.AndroidManifest.expected
index c43cfff..7c44350 100644
--- a/chrome/android/expectations/trichrome_chrome_bundle__base.AndroidManifest.expected
+++ b/chrome/android/expectations/trichrome_chrome_bundle__base.AndroidManifest.expected
@@ -16,6 +16,7 @@
   </queries>  # DIFF-ANCHOR: 9588fea7
   <uses-feature android:glEsVersion="0x00020000"/>
   <uses-feature android:name="android.hardware.camera" android:required="false"/>
+  <uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
   <uses-feature android:name="android.hardware.location.gps" android:required="false"/>
   <uses-feature android:name="android.hardware.microphone" android:required="false"/>
   <uses-feature android:name="android.hardware.screen.landscape" android:required="false"/>
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/SingleTabSwitcherMediator.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/SingleTabSwitcherMediator.java
index 475cf86..ba27390 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/SingleTabSwitcherMediator.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/SingleTabSwitcherMediator.java
@@ -79,8 +79,8 @@
         mPropertyModel.set(CLICK_LISTENER, v -> {
             if (mTabSelectingListener != null
                     && mTabModelSelector.getCurrentTabId() != TabList.INVALID_TAB_INDEX) {
-                selectTheCurrentTab();
                 StartSurfaceUserData.setOpenedFromStart(mTabModelSelector.getCurrentTab());
+                selectTheCurrentTab();
             }
         });
         mPropertyModel.addObserver((source, key) -> {
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index 7b3d6d29..c113882 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -131,14 +131,13 @@
     {% block extra_uses_permissions %}
     {% endblock %}
 
-    <!-- We may use GPS but it's not required -->
+    <!-- Features related to permissions we request. -->
+    <!-- android.permission.ACCESS_FINE_LOCATION -->
     <uses-feature android:name="android.hardware.location.gps" android:required="false" />
+    <!-- android.permission.CAMERA -->
     <uses-feature android:name="android.hardware.camera" android:required="false" />
-
-    <!--
-      android.permission.RECORD_AUDIO makes this implied, however we don't
-      require a microphone.
-    -->
+    <uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
+    <!-- android.permission.RECORD_AUDIO -->
     <uses-feature android:name="android.hardware.microphone" android:required="false" />
     <!--
       The app is usable with keyboard/mouse. This feature is implicitly true for
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
index 4ccb112..f38b9c54c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
@@ -445,10 +445,10 @@
                 ()
                         -> AssistantVoiceSearchService.reportStartupUserEligibility(
                                 ContextUtils.getApplicationContext()));
-        deferredStartupHandler.addDeferredTask(
-                () -> GlobalAppLocaleController.getInstance().recordOverrideLanguageMetrics());
-        deferredStartupHandler.addDeferredTask(
-                () -> GlobalAppLocaleController.getInstance().maybeSetupLocaleManager());
+        deferredStartupHandler.addDeferredTask(() -> {
+            GlobalAppLocaleController.getInstance().maybeSetupLocaleManager();
+            GlobalAppLocaleController.getInstance().recordOverrideLanguageMetrics();
+        });
         deferredStartupHandler.addDeferredTask(() -> {
             // OptimizationTypes which we give a guarantee will be registered when we pass the
             // onDeferredStartup() signal to OptimizationGuide.
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 73cad483..3c39d25 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
@@ -102,7 +102,6 @@
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabBrowserControlsConstraintsHelper;
 import org.chromium.chrome.browser.tab.TabObscuringHandler;
-import org.chromium.chrome.browser.tab.TabObserver;
 import org.chromium.chrome.browser.tab.TabSelectionType;
 import org.chromium.chrome.browser.tab.state.ShoppingPersistedTabData;
 import org.chromium.chrome.browser.tabmodel.IncognitoStateProvider;
@@ -223,7 +222,6 @@
 
     private LayoutManagerImpl mLayoutManager;
 
-    private TabObserver mTabObserver;
     private BookmarkModelObserver mBookmarksObserver;
     private FindToolbarObserver mFindToolbarObserver;
 
@@ -1530,12 +1528,6 @@
         mToolbar.removeUrlExpansionObserver(mStatusBarColorController);
         mToolbar.destroy();
 
-        if (mTabObserver != null) {
-            Tab currentTab = mLocationBarModel.getTab();
-            if (currentTab != null) currentTab.removeObserver(mTabObserver);
-            mTabObserver = null;
-        }
-
         mIncognitoStateProvider.destroy();
         mTabCountProvider.destroy();
 
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 909d689..343c982 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -7620,9 +7620,16 @@
           Energy Saver turned on
         </message>
       </if>
-      <message name="IDS_BATTERY_SAVER_MODE_PROMO_TEXT" desc="The text shown for the battery saver mode in-product promo bubble.">
-        This extends battery power by limiting background activity and visual effects like smooth scrolling
-      </message>
+      <if expr="use_titlecase">
+        <message name="IDS_BATTERY_SAVER_MODE_PROMO_TEXT" desc="The text shown for the battery saver mode in-product promo bubble.">
+          This extends battery power by limiting background activity and visual effects like smooth scrolling.
+        </message>
+      </if>
+      <if expr="not use_titlecase">
+        <message name="IDS_BATTERY_SAVER_MODE_PROMO_TEXT" desc="The text shown for the battery saver mode in-product promo bubble.">
+          This extends battery power by limiting background activity and visual effects like smooth scrolling
+        </message>
+      </if>
       <message name="IDS_BATTERY_SAVER_MODE_PROMO_ACTION_TEXT" desc="The custom action button text for the battery saver mode in-product promo bubble.">
         Settings
       </message>
@@ -7632,9 +7639,16 @@
       <message name="IDS_HIGH_EFFICIENCY_INFO_MODE_PROMO_ACTION_TEXT" desc="The custom action button text for the high efficiency info mode in-product promo bubble.">
         Settings
       </message>
-      <message name="IDS_HIGH_EFFICIENCY_MODE_PROMO_TEXT" desc="The text shown for the high efficiency mode in-product promo bubble">
-        Memory Saver frees up memory from inactive tabs so it can be used by active tabs and other apps
-      </message>
+      <if expr="use_titlecase">
+        <message name="IDS_HIGH_EFFICIENCY_MODE_PROMO_TEXT" desc="The text shown for the high efficiency mode in-product promo bubble">
+          Memory Saver frees up memory from inactive tabs so it can be used by active tabs and other apps.
+        </message>
+      </if>
+      <if expr="not use_titlecase">
+        <message name="IDS_HIGH_EFFICIENCY_MODE_PROMO_TEXT" desc="The text shown for the high efficiency mode in-product promo bubble">
+          Memory Saver frees up memory from inactive tabs so it can be used by active tabs and other apps
+        </message>
+      </if>
       <if expr="use_titlecase">
         <message name="IDS_HIGH_EFFICIENCY_MODE_PROMO_ACTION_TEXT" desc="In Title Case: The custom action button text for the high efficiency mode in-product promo bubble">
           Turn On
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp
index 58e3d460..fdfa6c9 100644
--- a/chrome/app/os_settings_strings.grdp
+++ b/chrome/app/os_settings_strings.grdp
@@ -2621,18 +2621,6 @@
   <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTER_SELECT_DRIVER" desc="Label for the file selector to manually select a PPD file from the user's file system.">
     Or specify your printer PPD <ph name="LINK_BEGIN">&lt;a&gt;</ph>Learn more<ph name="LINK_END">&lt;/a&gt;</ph>
   </message>
-  <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTER_EDIT_SELECT_DRIVER" desc="Label for the file selector to manually select a PPD file from the user's file system.">
-    Or specify your printer PPD
-  </message>
-  <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTERS_VIEW_PPD" desc="Text for the button which allows the user to view the PPD for the active printer.">
-    View PPD
-  </message>
-  <message name="IDS_SETTINGS_PRINTING_CUPS_VIEW_PPD_ERROR_MESSAGE" desc="The message shown when the request to view a PPD is unsuccessful.">
-    Unable to retrieve PPD.
-  </message>
-  <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTERS_PPD_INTRO" desc="Text used to introduce the PPD for an active printer.">
-    PPD for <ph name="PRINTER_NAME">$1<ex>Acme Printer</ex></ph>
-  </message>
   <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTER_BUTTON_SELECT_DRIVER_ARIA_LABEL" desc="ARIA label for the file selector button to manually select a PPD file from the user's file system. This text will not be visual on any page. It will only be spoken by screen readers.">
     Browse to specify your printer PPD
   </message>
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PRINTING_CUPS_PRINTERS_PPD_INTRO.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PRINTING_CUPS_PRINTERS_PPD_INTRO.png.sha1
deleted file mode 100644
index c3ae0a7..0000000
--- a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PRINTING_CUPS_PRINTERS_PPD_INTRO.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-6e41a67cd680ce4ad4a993140e6ce90a7bd2d92d
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PRINTING_CUPS_PRINTERS_VIEW_PPD.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PRINTING_CUPS_PRINTERS_VIEW_PPD.png.sha1
deleted file mode 100644
index da24a86..0000000
--- a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PRINTING_CUPS_PRINTERS_VIEW_PPD.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-051a90d25b9329ffdfb0da3f6413dc27bf0f5b0d
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PRINTING_CUPS_PRINTER_EDIT_SELECT_DRIVER.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PRINTING_CUPS_PRINTER_EDIT_SELECT_DRIVER.png.sha1
deleted file mode 100644
index da24a86..0000000
--- a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PRINTING_CUPS_PRINTER_EDIT_SELECT_DRIVER.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-051a90d25b9329ffdfb0da3f6413dc27bf0f5b0d
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PRINTING_CUPS_VIEW_PPD_ERROR_MESSAGE.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PRINTING_CUPS_VIEW_PPD_ERROR_MESSAGE.png.sha1
deleted file mode 100644
index c3ae0a7..0000000
--- a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PRINTING_CUPS_VIEW_PPD_ERROR_MESSAGE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-6e41a67cd680ce4ad4a993140e6ce90a7bd2d92d
\ No newline at end of file
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 38a0dd9e..9eb25a91 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3138,70 +3138,37 @@
      std::size(kQuickDim10sQuickLock130sFeedback), nullptr},
 };
 
-const FeatureEntry::FeatureParam kVCBackgroundBlurScale15Sample4[] = {
-    {"blur_scale", "0.15"},
-    {"blur_samples", "4"},
+const FeatureEntry::FeatureParam kVCBackgroundBlurLowest[] = {
+    {"blur_level", "lowest"},
 };
 
-const FeatureEntry::FeatureParam kVCBackgroundBlurScale15Sample8[] = {
-    {"blur_scale", "0.15"},
-    {"blur_samples", "8"},
+const FeatureEntry::FeatureParam kVCBackgroundBlurLight[] = {
+    {"blur_level", "light"},
 };
 
-const FeatureEntry::FeatureParam kVCBackgroundBlurScale15Sample16[] = {
-    {"blur_scale", "0.15"},
-    {"blur_samples", "16"},
+const FeatureEntry::FeatureParam kVCBackgroundBlurMedium[] = {
+    {"blur_level", "medium"},
 };
 
-const FeatureEntry::FeatureParam kVCBackgroundBlurScale25Sample4[] = {
-    {"blur_scale", "0.25"},
-    {"blur_samples", "4"},
+const FeatureEntry::FeatureParam kVCBackgroundBlurHeavy[] = {
+    {"blur_level", "heavy"},
 };
 
-const FeatureEntry::FeatureParam kVCBackgroundBlurScale25Sample8[] = {
-    {"blur_scale", "0.25"},
-    {"blur_samples", "8"},
-};
-
-const FeatureEntry::FeatureParam kVCBackgroundBlurScale25Sample16[] = {
-    {"blur_scale", "0.25"},
-    {"blur_samples", "16"},
-};
-
-const FeatureEntry::FeatureParam kVCBackgroundBlurScale35Sample4[] = {
-    {"blur_scale", "0.35"},
-    {"blur_samples", "4"},
-};
-
-const FeatureEntry::FeatureParam kVCBackgroundBlurScale35Sample8[] = {
-    {"blur_scale", "0.35"},
-    {"blur_samples", "8"},
-};
-
-const FeatureEntry::FeatureParam kVCBackgroundBlurScale35Sample16[] = {
-    {"blur_scale", "0.35"},
-    {"blur_samples", "16"},
+const FeatureEntry::FeatureParam kVCBackgroundBlurMaximum[] = {
+    {"blur_level", "maximum"},
 };
 
 const FeatureEntry::FeatureVariation kVCBackgroundBlurVariations[] = {
-    {"Scale15Sample4", kVCBackgroundBlurScale15Sample4,
-     std::size(kVCBackgroundBlurScale15Sample4), nullptr},
-    {"Scale15Sample8", kVCBackgroundBlurScale15Sample8,
-     std::size(kVCBackgroundBlurScale15Sample8), nullptr},
-    {"Scale15Sample16", kVCBackgroundBlurScale15Sample16,
-     std::size(kVCBackgroundBlurScale15Sample16), nullptr},
-    {"Scale25Sample4", kVCBackgroundBlurScale25Sample4,
-     std::size(kVCBackgroundBlurScale25Sample4), nullptr},
-    {"Scale25Sample8", kVCBackgroundBlurScale25Sample8,
-     std::size(kVCBackgroundBlurScale25Sample8), nullptr},
-    {"Scale25Sample16", kVCBackgroundBlurScale25Sample16,
-     std::size(kVCBackgroundBlurScale25Sample16), nullptr},
-    {"Scale35Sample4", kVCBackgroundBlurScale35Sample4,
-     std::size(kVCBackgroundBlurScale35Sample4), nullptr},
-    {"Scale35Sample8", kVCBackgroundBlurScale35Sample8,
-     std::size(kVCBackgroundBlurScale35Sample8), nullptr},
-    {"Scale35Sample16", kVCBackgroundBlurScale35Sample16,
-     std::size(kVCBackgroundBlurScale35Sample16), nullptr},
+    {"Lowest Blur", kVCBackgroundBlurLowest, std::size(kVCBackgroundBlurLowest),
+     nullptr},
+    {"Light Blur", kVCBackgroundBlurLight, std::size(kVCBackgroundBlurLight),
+     nullptr},
+    {"Medium Blur", kVCBackgroundBlurMedium, std::size(kVCBackgroundBlurMedium),
+     nullptr},
+    {"Heavy Blur", kVCBackgroundBlurHeavy, std::size(kVCBackgroundBlurHeavy),
+     nullptr},
+    {"Maximum Blur", kVCBackgroundBlurMaximum,
+     std::size(kVCBackgroundBlurMaximum), nullptr},
 };
 
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
@@ -8990,6 +8957,14 @@
      FEATURE_WITH_PARAMS_VALUE_TYPE(ash::features::kVCBackgroundBlur,
                                     kVCBackgroundBlurVariations,
                                     "VCBackgroundBlur")},
+
+    {"vc-background-replace", flag_descriptions::kVCBackgroundReplaceName,
+     flag_descriptions::kVCBackgroundReplaceDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(ash::features::kVCBackgroundReplace)},
+
+    {"vc-portrait-relighting", flag_descriptions::kVCPortraitRelightingName,
+     flag_descriptions::kVCPortraitRelightingDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(ash::features::kVCPortraitRelighting)},
 #endif
 
 #if BUILDFLAG(IS_WIN)
@@ -9729,6 +9704,9 @@
     {"vc-controls-ui", flag_descriptions::kVcControlsUiName,
      flag_descriptions::kVcControlsUiDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(chromeos::features::kVcControlsUi)},
+    {"enable-16-desks", flag_descriptions::kDesks16Name,
+     flag_descriptions::kDesks16Description, kOsCrOS,
+     FEATURE_VALUE_TYPE(ash::features::kEnable16Desks)},
 #endif
 
     // NOTE: Adding a new flag requires adding a corresponding entry to enum
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn
index 869719c4..2d8ad852 100644
--- a/chrome/browser/ash/BUILD.gn
+++ b/chrome/browser/ash/BUILD.gn
@@ -3540,6 +3540,7 @@
     "//chromeos/ime:gencode",
     "//chromeos/services/machine_learning/public/cpp",
     "//chromeos/services/network_config:in_process_instance",
+    "//chromeos/services/network_health:in_process_instance",
     "//chromeos/strings",
     "//chromeos/ui/vector_icons",
     "//chromeos/utils",
diff --git a/chrome/browser/ash/drive/drive_integration_service_browser_test_base.cc b/chrome/browser/ash/drive/drive_integration_service_browser_test_base.cc
index 5f7ca754..05811c77 100644
--- a/chrome/browser/ash/drive/drive_integration_service_browser_test_base.cc
+++ b/chrome/browser/ash/drive/drive_integration_service_browser_test_base.cc
@@ -91,7 +91,8 @@
   GetFakeDriveFsForProfile(profile)->SetMetadata(
       relative_to_drive_fs_mount, "text/plain",
       relative_to_drive_fs_mount.BaseName().value(),
-      /*pinned=*/false, /*shared=*/false, /*capabilities=*/{},
+      /*pinned=*/false, /*available_offline=*/false, /*shared=*/false,
+      /*capabilities=*/{},
       /*folder_feature=*/{}, drive_file_id, /*alternate_url=*/"");
 
   // Update the relative/absolute paths to the generated file.
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest.cc b/chrome/browser/ash/file_manager/file_manager_browsertest.cc
index de057e2e..d884cb1 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest.cc
@@ -177,6 +177,11 @@
     return *this;
   }
 
+  TestCase& EnableInlineStatusSync() {
+    options.enable_inline_status_sync = true;
+    return *this;
+  }
+
   TestCase& EnableFileTransferConnector() {
     options.enable_file_transfer_connector = true;
     return *this;
@@ -226,6 +231,9 @@
     if (options.enable_mirrorsync)
       full_name += "_MirrorSync";
 
+    if (options.enable_inline_status_sync)
+      full_name += "_InlineStatusSync";
+
     if (options.file_transfer_connector_report_only)
       full_name += "_ReportOnly";
 
@@ -1187,7 +1195,8 @@
         TestCase("driveLinkOpenFileThroughTransitiveLink"),
         TestCase("driveWelcomeBanner"),
         TestCase("driveOfflineInfoBanner").EnableDriveDssPin(),
-        TestCase("driveOfflineInfoBannerWithoutFlag")
+        TestCase("driveOfflineInfoBannerWithoutFlag"),
+        TestCase("driveInlineSyncStatus").EnableInlineStatusSync()
         // TODO(b/189173190): Enable
         // TestCase("driveEnableDocsOfflineDialog"),
         // TODO(b/189173190): Enable
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc b/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
index 6fb1c27..2618ffac 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
@@ -416,7 +416,8 @@
     EntryCapabilities capabilities;   // Entry permissions.
     EntryFolderFeature folder_feature;  // Entry folder feature.
     bool pinned = false;                // Whether the file should be pinned.
-    std::string alternate_url;          // Entry's alternate URL on Drive.
+    bool available_offline = false;  // Whether the file is available_offline.
+    std::string alternate_url;       // Entry's alternate URL on Drive.
 
     TestEntryInfo& SetSharedOption(SharedOption option) {
       shared_option = option;
@@ -465,6 +466,11 @@
       return *this;
     }
 
+    TestEntryInfo& SetAvailableOffline(bool is_available_offline) {
+      available_offline = is_available_offline;
+      return *this;
+    }
+
     TestEntryInfo& SetAlternateUrl(const std::string& new_alternate_url) {
       alternate_url = new_alternate_url;
       return *this;
@@ -497,6 +503,8 @@
       converter->RegisterNestedField("folderFeature",
                                      &TestEntryInfo::folder_feature);
       converter->RegisterBoolField("pinned", &TestEntryInfo::pinned);
+      converter->RegisterBoolField("availableOffline",
+                                   &TestEntryInfo::available_offline);
       converter->RegisterStringField("alternateUrl",
                                      &TestEntryInfo::alternate_url);
     }
@@ -1275,6 +1283,7 @@
     }
     fake_drivefs_helper_->fake_drivefs().SetMetadata(
         relative_path, entry.mime_type, original_name.value(), entry.pinned,
+        entry.available_offline,
         entry.shared_option == AddEntriesMessage::SharedOption::SHARED ||
             entry.shared_option ==
                 AddEntriesMessage::SharedOption::SHARED_WITH_ME,
@@ -1295,6 +1304,19 @@
                                           base::Unretained(this)));
   }
 
+  void SetFileSyncStatus(const std::string* path,
+                         const drivefs::mojom::ItemEvent::State sync_status) {
+    drivefs::mojom::SyncingStatus syncing_status;
+    syncing_status.item_events.emplace_back(
+        absl::in_place, /* stable_id */ 1, /* group_id */ 1, *path, sync_status,
+        /* bytes_transferred */ 50, /* bytes_to_transfer */ 100,
+        drivefs::mojom::ItemEventReason::kTransfer);
+
+    auto& drivefs_delegate = fake_drivefs_helper_->fake_drivefs().delegate();
+    drivefs_delegate->OnSyncingStatusUpdate(syncing_status.Clone());
+    drivefs_delegate.FlushForTesting();
+  }
+
   absl::optional<drivefs::mojom::DialogResult> last_dialog_result() {
     return last_dialog_result_;
   }
@@ -1937,6 +1959,12 @@
     disabled_features.push_back(chromeos::features::kDriveFsMirroring);
   }
 
+  if (options.enable_inline_status_sync) {
+    enabled_features.push_back(chromeos::features::kFilesInlineSyncStatus);
+  } else {
+    disabled_features.push_back(chromeos::features::kFilesInlineSyncStatus);
+  }
+
   if (options.enable_upload_office_to_cloud) {
     enabled_features.push_back(chromeos::features::kUploadOfficeToCloud);
   } else {
@@ -3014,6 +3042,11 @@
     return;
   }
 
+  if (name == "isInlineStatusSyncEnabled") {
+    *output = options.enable_inline_status_sync ? "true" : "false";
+    return;
+  }
+
   if (name == "switchLanguage") {
     const std::string* language = value.FindString("language");
     ASSERT_TRUE(language);
@@ -3132,6 +3165,22 @@
     return;
   }
 
+  if (name == "setDriveFileSyncStatus") {
+    auto* sync_status = value.FindString("syncStatus");
+    auto* path = value.FindString("path");
+    ASSERT_TRUE(sync_status);
+    ASSERT_TRUE(path);
+    drive_volume_->SetFileSyncStatus(
+        path, *sync_status == "in_progress"
+                  ? drivefs::mojom::ItemEvent::State::kInProgress
+              : *sync_status == "queued"
+                  ? drivefs::mojom::ItemEvent::State::kQueued
+              : *sync_status == "completed"
+                  ? drivefs::mojom::ItemEvent::State::kCompleted
+                  : drivefs::mojom::ItemEvent::State::kFailed);
+    return;
+  }
+
   if (name == "getLastDriveDialogResult") {
     absl::optional<drivefs::mojom::DialogResult> result =
         drive_volume_->last_dialog_result();
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest_base.h b/chrome/browser/ash/file_manager/file_manager_browsertest_base.h
index ea248c7..7f631f3 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest_base.h
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest_base.h
@@ -133,6 +133,9 @@
     // Whether test should run with the DriveFsMirroring flag.
     bool enable_mirrorsync = false;
 
+    // Whether test should run with the FilesInlineSyncStatus flag.
+    bool enable_inline_status_sync = false;
+
     // Whether test should enable the file transfer connector.
     bool enable_file_transfer_connector = false;
 
diff --git a/chrome/browser/ash/login/saml/in_session_password_change_manager.cc b/chrome/browser/ash/login/saml/in_session_password_change_manager.cc
index a9481ab..255343f 100644
--- a/chrome/browser/ash/login/saml/in_session_password_change_manager.cc
+++ b/chrome/browser/ash/login/saml/in_session_password_change_manager.cc
@@ -17,7 +17,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part_ash.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_dialogs.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/password_change_dialogs.h"
 #include "chrome/common/chrome_features.h"
 #include "chromeos/ash/components/login/auth/public/user_context.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/ash/login/saml/in_session_password_sync_manager.h b/chrome/browser/ash/login/saml/in_session_password_sync_manager.h
index 20b1552..d5abc3c5 100644
--- a/chrome/browser/ash/login/saml/in_session_password_sync_manager.h
+++ b/chrome/browser/ash/login/saml/in_session_password_sync_manager.h
@@ -12,7 +12,7 @@
 #include "base/time/clock.h"
 #include "chrome/browser/ash/login/saml/password_sync_token_fetcher.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_reauth_dialogs.h"
 #include "chromeos/ash/components/login/auth/auth_status_consumer.h"
 #include "chromeos/ash/components/login/auth/public/user_context.h"
 #include "chromeos/ash/components/proximity_auth/screenlock_bridge.h"
diff --git a/chrome/browser/ash/login/saml/lockscreen_reauth_dialog_test_helper.cc b/chrome/browser/ash/login/saml/lockscreen_reauth_dialog_test_helper.cc
index cee7393..a7221e2 100644
--- a/chrome/browser/ash/login/saml/lockscreen_reauth_dialog_test_helper.cc
+++ b/chrome/browser/ash/login/saml/lockscreen_reauth_dialog_test_helper.cc
@@ -13,11 +13,11 @@
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_captive_portal_dialog.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_dialog.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_ui.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_start_reauth_ui.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_captive_portal_dialog.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_dialog.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_ui.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_reauth_dialogs.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_start_reauth_ui.h"
 #include "chrome/browser/ui/webui/signin/signin_utils.h"
 #include "components/session_manager/core/session_manager.h"
 #include "content/public/test/browser_test_utils.h"
@@ -327,7 +327,7 @@
   if (!network_dialog_ || !network_dialog_->GetWebUIForTest()) {
     ADD_FAILURE() << "Could not retrieve LockScreenNetworkDialog";
   }
-  network_webui_controller_ = static_cast<chromeos::LockScreenNetworkUI*>(
+  network_webui_controller_ = static_cast<LockScreenNetworkUI*>(
       network_dialog_->GetWebUIForTest()->GetController());
   if (!network_webui_controller_) {
     ADD_FAILURE() << "Could not retrieve LockScreenNetworkUI";
diff --git a/chrome/browser/ash/login/saml/lockscreen_reauth_dialog_test_helper.h b/chrome/browser/ash/login/saml/lockscreen_reauth_dialog_test_helper.h
index 0fb2c3e..4a2a22c 100644
--- a/chrome/browser/ash/login/saml/lockscreen_reauth_dialog_test_helper.h
+++ b/chrome/browser/ash/login/saml/lockscreen_reauth_dialog_test_helper.h
@@ -9,16 +9,6 @@
 #include "chrome/browser/ash/login/test/js_checker.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
-namespace chromeos {
-class LockScreenStartReauthDialog;
-class LockScreenStartReauthUI;
-class LockScreenReauthHandler;
-class LockScreenNetworkDialog;
-class LockScreenNetworkUI;
-class LockScreenCaptivePortalDialog;
-class NetworkConfigMessageHandler;
-}  // namespace chromeos
-
 namespace content {
 class WebContents;
 }
@@ -26,6 +16,13 @@
 namespace ash {
 
 class InSessionPasswordSyncManager;
+class LockScreenStartReauthDialog;
+class LockScreenStartReauthUI;
+class LockScreenReauthHandler;
+class LockScreenNetworkDialog;
+class LockScreenNetworkUI;
+class LockScreenCaptivePortalDialog;
+class NetworkConfigMessageHandler;
 
 // Supports triggering the online re-authentication dialog on the Chrome OS lock
 // screen from browser tests and interacting with it.
@@ -149,21 +146,17 @@
 
   // Main Dialog
   base::raw_ptr<InSessionPasswordSyncManager> password_sync_manager_ = nullptr;
-  base::raw_ptr<chromeos::LockScreenStartReauthDialog> reauth_dialog_ = nullptr;
-  base::raw_ptr<chromeos::LockScreenStartReauthUI> reauth_webui_controller_ =
-      nullptr;
-  base::raw_ptr<chromeos::LockScreenReauthHandler> main_handler_ = nullptr;
+  base::raw_ptr<LockScreenStartReauthDialog> reauth_dialog_ = nullptr;
+  base::raw_ptr<LockScreenStartReauthUI> reauth_webui_controller_ = nullptr;
+  base::raw_ptr<LockScreenReauthHandler> main_handler_ = nullptr;
 
   // Network dialog which is owned by the main dialog.
-  base::raw_ptr<chromeos::LockScreenNetworkDialog> network_dialog_ = nullptr;
-  base::raw_ptr<chromeos::LockScreenNetworkUI> network_webui_controller_ =
-      nullptr;
-  base::raw_ptr<chromeos::NetworkConfigMessageHandler> network_handler_ =
-      nullptr;
+  base::raw_ptr<LockScreenNetworkDialog> network_dialog_ = nullptr;
+  base::raw_ptr<LockScreenNetworkUI> network_webui_controller_ = nullptr;
+  base::raw_ptr<NetworkConfigMessageHandler> network_handler_ = nullptr;
 
   // Captive portal dialog which is owned by the main dialog.
-  base::raw_ptr<chromeos::LockScreenCaptivePortalDialog>
-      captive_portal_dialog_ = nullptr;
+  base::raw_ptr<LockScreenCaptivePortalDialog> captive_portal_dialog_ = nullptr;
 };
 
 }  // namespace ash
diff --git a/chrome/browser/ash/login/saml/password_expiry_notification.cc b/chrome/browser/ash/login/saml/password_expiry_notification.cc
index 333ba1f..ff88127 100644
--- a/chrome/browser/ash/login/saml/password_expiry_notification.cc
+++ b/chrome/browser/ash/login/saml/password_expiry_notification.cc
@@ -24,7 +24,7 @@
 #include "chrome/browser/notifications/notification_display_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_ui.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/password_change_ui.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/ash/components/login/auth/public/saml_password_attributes.h"
 #include "chromeos/strings/grit/chromeos_strings.h"
diff --git a/chrome/browser/ash/net/network_health/network_health_manager.cc b/chrome/browser/ash/net/network_health/network_health_manager.cc
index 1094106e..a2b6d3c 100644
--- a/chrome/browser/ash/net/network_health/network_health_manager.cc
+++ b/chrome/browser/ash/net/network_health/network_health_manager.cc
@@ -7,14 +7,13 @@
 #include "base/no_destructor.h"
 #include "chrome/browser/ash/net/network_diagnostics/network_diagnostics.h"
 #include "chromeos/ash/components/dbus/debug_daemon/debug_daemon_client.h"
+#include "chromeos/services/network_health/in_process_instance.h"
 #include "chromeos/services/network_health/network_health_service.h"
 
 namespace ash {
 namespace network_health {
 
 NetworkHealthManager::NetworkHealthManager() {
-  network_health_service_ =
-      std::make_unique<chromeos::network_health::NetworkHealthService>();
   network_diagnostics_ =
       std::make_unique<network_diagnostics::NetworkDiagnostics>(
           DebugDaemonClient::Get());
@@ -41,7 +40,8 @@
 void NetworkHealthManager::BindHealthReceiver(
     mojo::PendingReceiver<chromeos::network_health::mojom::NetworkHealthService>
         receiver) {
-  network_health_service_->BindReceiver(std::move(receiver));
+  chromeos::network_health::GetInProcessInstance()->BindReceiver(
+      std::move(receiver));
 }
 
 void NetworkHealthManager::BindDiagnosticsReceiver(
@@ -54,7 +54,8 @@
 void NetworkHealthManager::AddObserver(
     mojo::PendingRemote<chromeos::network_health::mojom::NetworkEventsObserver>
         observer) {
-  network_health_service_->AddObserver(std::move(observer));
+  chromeos::network_health::GetInProcessInstance()->AddObserver(
+      std::move(observer));
 }
 
 NetworkHealthManager* NetworkHealthManager::GetInstance() {
diff --git a/chrome/browser/ash/net/network_health/network_health_manager.h b/chrome/browser/ash/net/network_health/network_health_manager.h
index 3bdc5b1d..6da030e 100644
--- a/chrome/browser/ash/net/network_health/network_health_manager.h
+++ b/chrome/browser/ash/net/network_health/network_health_manager.h
@@ -47,8 +47,6 @@
           chromeos::network_health::mojom::NetworkEventsObserver> observer);
 
  private:
-  std::unique_ptr<chromeos::network_health::NetworkHealthService>
-      network_health_service_;
   std::unique_ptr<network_diagnostics::NetworkDiagnostics> network_diagnostics_;
 };
 
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc
index 6c04eed..bd12a18 100644
--- a/chrome/browser/chrome_browser_interface_binders.cc
+++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -31,6 +31,7 @@
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/ssl/security_state_tab_helper.h"
 #include "chrome/browser/translate/translate_frame_binder.h"
+#include "chrome/browser/ui/search_engines/search_engine_tab_helper.h"
 #include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/web_applications/draggable_region_host_impl.h"
 #include "chrome/browser/ui/web_applications/sub_apps_service_impl.h"
@@ -264,8 +265,8 @@
 #include "chrome/browser/ui/webui/ash/crostini_upgrader/crostini_upgrader_ui.h"
 #include "chrome/browser/ui/webui/ash/emoji/emoji_picker.mojom.h"
 #include "chrome/browser/ui/webui/ash/emoji/emoji_ui.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_ui.h"
 #include "chrome/browser/ui/webui/chromeos/bluetooth_pairing_dialog.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_ui.h"
 #include "chrome/browser/ui/webui/chromeos/internet_config_dialog.h"
 #include "chrome/browser/ui/webui/chromeos/internet_detail_dialog.h"
 #include "chrome/browser/ui/webui/chromeos/launcher_internals/launcher_internals.mojom.h"
@@ -726,6 +727,10 @@
   map->Add<payments::mojom::PaymentCredential>(
       base::BindRepeating(&payments::CreatePaymentCredential));
 
+  map->Add<chrome::mojom::OpenSearchDescriptionDocumentHandler>(
+      base::BindRepeating(
+          &SearchEngineTabHelper::BindOpenSearchDescriptionDocumentHandler));
+
 #if BUILDFLAG(IS_ANDROID)
   map->Add<blink::mojom::InstalledAppProvider>(base::BindRepeating(
       &ForwardToJavaFrame<blink::mojom::InstalledAppProvider>));
@@ -1112,7 +1117,7 @@
 #endif  // BUILDFLAG(PLATFORM_CFM)
       chromeos::InternetConfigDialogUI, chromeos::InternetDetailDialogUI,
       chromeos::NetworkUI, chromeos::OobeUI, ash::settings::OSSettingsUI,
-      chromeos::LockScreenNetworkUI, ash::ShimlessRMADialogUI>(map);
+      ash::LockScreenNetworkUI, ash::ShimlessRMADialogUI>(map);
 
   RegisterWebUIControllerInterfaceBinder<
       ash::printing::printing_manager::mojom::PrintingMetadataProvider,
diff --git a/chrome/browser/chrome_content_browser_client_receiver_bindings.cc b/chrome/browser/chrome_content_browser_client_receiver_bindings.cc
index 68d7f9f..3cadf58d 100644
--- a/chrome/browser/chrome_content_browser_client_receiver_bindings.cc
+++ b/chrome/browser/chrome_content_browser_client_receiver_bindings.cc
@@ -22,7 +22,6 @@
 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
 #include "chrome/browser/predictors/loading_predictor.h"
 #include "chrome/browser/predictors/loading_predictor_factory.h"
-#include "chrome/browser/ui/search_engines/search_engine_tab_helper.h"
 #include "chrome/common/buildflags.h"
 #include "components/autofill/content/browser/content_autofill_driver_factory.h"
 #include "components/autofill_assistant/content/browser/content_autofill_assistant_driver.h"
@@ -505,15 +504,6 @@
                 std::move(receiver), render_frame_host);
           },
           &render_frame_host));
-  associated_registry.AddInterface<
-      chrome::mojom::OpenSearchDescriptionDocumentHandler>(base::BindRepeating(
-      [](content::RenderFrameHost* render_frame_host,
-         mojo::PendingAssociatedReceiver<
-             chrome::mojom::OpenSearchDescriptionDocumentHandler> receiver) {
-        SearchEngineTabHelper::BindOpenSearchDescriptionDocumentHandler(
-            std::move(receiver), render_frame_host);
-      },
-      &render_frame_host));
 #if BUILDFLAG(ENABLE_PLUGINS)
   associated_registry.AddInterface<
       chrome::mojom::PluginAuthHost>(base::BindRepeating(
diff --git a/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc b/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc
index 915f5d4..c23720f 100644
--- a/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc
+++ b/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc
@@ -380,8 +380,8 @@
       << message_;
 }
 
-IN_PROC_BROWSER_TEST_F(FileSystemProviderServiceWorkerApiTest, MoveEntry) {
-  ASSERT_TRUE(RunExtensionTest("file_system_provider/service_worker/move_entry",
+IN_PROC_BROWSER_TEST_F(FileSystemProviderServiceWorkerApiTest, Evil) {
+  ASSERT_TRUE(RunExtensionTest("file_system_provider/service_worker/evil",
                                {.extension_url = "test.html"},
                                {.load_as_component = true}))
       << message_;
@@ -394,6 +394,13 @@
       << message_;
 }
 
+IN_PROC_BROWSER_TEST_F(FileSystemProviderServiceWorkerApiTest, MoveEntry) {
+  ASSERT_TRUE(RunExtensionTest("file_system_provider/service_worker/move_entry",
+                               {.extension_url = "test.html"},
+                               {.load_as_component = true}))
+      << message_;
+}
+
 IN_PROC_BROWSER_TEST_F(FileSystemProviderServiceWorkerApiTest, ReadDirectory) {
   ASSERT_TRUE(RunExtensionTest(
       "file_system_provider/service_worker/read_directory",
diff --git a/chrome/browser/commerce/android/BUILD.gn b/chrome/browser/commerce/android/BUILD.gn
index a8d8340..4d0b4a1 100644
--- a/chrome/browser/commerce/android/BUILD.gn
+++ b/chrome/browser/commerce/android/BUILD.gn
@@ -71,6 +71,4 @@
   sources = [
     "java/src/org/chromium/chrome/browser/commerce/ShoppingServiceFactory.java",
   ]
-
-  deps = [ "//components/commerce/core:shopping_service" ]
 }
diff --git a/chrome/browser/extensions/api/platform_keys/platform_keys_api.cc b/chrome/browser/extensions/api/platform_keys/platform_keys_api.cc
index 02de2c7..37fec1c 100644
--- a/chrome/browser/extensions/api/platform_keys/platform_keys_api.cc
+++ b/chrome/browser/extensions/api/platform_keys/platform_keys_api.cc
@@ -267,15 +267,14 @@
     result_match.certificate.assign(der_encoded_cert.begin(),
                                     der_encoded_cert.end());
 
-    absl::optional<base::DictionaryValue> algorithm =
+    absl::optional<base::Value::Dict> algorithm =
         BuildWebCrypAlgorithmDictionary(key_info);
     if (!algorithm) {
       LOG(ERROR) << "Skipping unsupported certificate with key type "
                  << key_info.key_type;
       continue;
     }
-    result_match.key_algorithm.additional_properties =
-        std::move(algorithm->GetDict());
+    result_match.key_algorithm.additional_properties = std::move(*algorithm);
 
     result_matches.push_back(std::move(result_match));
   }
@@ -323,14 +322,14 @@
   }
 
   api_pki::GetPublicKey::Results::Algorithm algorithm;
-  absl::optional<base::DictionaryValue> dict =
+  absl::optional<base::Value::Dict> dict =
       crosapi::keystore_service_util::DictionaryFromSigningAlgorithm(
           result->get_success_result()->algorithm_properties);
   if (!dict) {
     Respond(Error(kErrorInvalidSigningAlgorithm));
     return;
   }
-  algorithm.additional_properties = std::move(dict->GetDict());
+  algorithm.additional_properties = std::move(*dict);
   Respond(ArgumentList(api_pki::GetPublicKey::Results::Create(
       result->get_success_result()->public_key, std::move(algorithm))));
 }
@@ -374,10 +373,10 @@
     return RespondNow(Error(StatusToString(check_result)));
 
   api_pki::GetPublicKeyBySpki::Results::Algorithm algorithm;
-  absl::optional<base::DictionaryValue> algorithm_dictionary =
+  absl::optional<base::Value::Dict> algorithm_dictionary =
       chromeos::platform_keys::BuildWebCrypAlgorithmDictionary(key_info);
   DCHECK(algorithm_dictionary);
-  algorithm.additional_properties = std::move(algorithm_dictionary->GetDict());
+  algorithm.additional_properties = std::move(*algorithm_dictionary);
 
   return RespondNow(ArgumentList(api_pki::GetPublicKeyBySpki::Results::Create(
       public_key_spki_der, algorithm)));
diff --git a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
index 9a3dae4f..b59fcd0c 100644
--- a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
+++ b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
@@ -597,6 +597,10 @@
       base::FeatureList::IsEnabled(
           chromeos::features::kSystemJapanesePhysicalTyping)));
   features.Append(GenerateFeatureFlag(
+      "languageSettingsUpdateJapanese",
+      base::FeatureList::IsEnabled(
+          chromeos::features::kCrosLanguageSettingsUpdateJapanese)));
+  features.Append(GenerateFeatureFlag(
       "multilingualtyping",
       base::FeatureList::IsEnabled(chromeos::features::kMultilingualTyping)));
   features.Append(
diff --git a/chrome/browser/feed/android/feed_stream.cc b/chrome/browser/feed/android/feed_stream.cc
index d57efb4..35ea31a1 100644
--- a/chrome/browser/feed/android/feed_stream.cc
+++ b/chrome/browser/feed/android/feed_stream.cc
@@ -39,16 +39,30 @@
                                  jint stream_kind,
                                  jlong native_feed_reliability_logging_bridge) {
   return reinterpret_cast<intptr_t>(
-      new FeedStream(j_this, stream_kind,
+      new FeedStream(j_this, stream_kind, std::string(),
                      reinterpret_cast<FeedReliabilityLoggingBridge*>(
                          native_feed_reliability_logging_bridge)));
 }
 
+static jlong JNI_FeedStream_InitWebFeed(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& j_this,
+    const JavaParamRef<jbyteArray>& j_web_feed_id,
+    jlong native_feed_reliability_logging_bridge) {
+  std::string web_feed_id;
+  base::android::JavaByteArrayToString(env, j_web_feed_id, &web_feed_id);
+  return reinterpret_cast<intptr_t>(new FeedStream(
+      j_this, static_cast<jint>(StreamKind::kChannel), web_feed_id,
+      reinterpret_cast<FeedReliabilityLoggingBridge*>(
+          native_feed_reliability_logging_bridge)));
+}
+
 FeedStream::FeedStream(const JavaRef<jobject>& j_this,
                        jint stream_kind,
+                       std::string web_feed_id,
                        FeedReliabilityLoggingBridge* reliability_logging_bridge)
-    : ::feed::FeedStreamSurface(
-          StreamType(static_cast<StreamKind>(stream_kind))),
+    : ::feed::FeedStreamSurface(StreamType(static_cast<StreamKind>(stream_kind),
+                                           std::move(web_feed_id))),
       feed_stream_api_(nullptr),
       reliability_logging_bridge_(reliability_logging_bridge) {
   java_ref_.Reset(j_this);
diff --git a/chrome/browser/feed/android/feed_stream.h b/chrome/browser/feed/android/feed_stream.h
index 37339a7..42feee3f 100644
--- a/chrome/browser/feed/android/feed_stream.h
+++ b/chrome/browser/feed/android/feed_stream.h
@@ -25,6 +25,7 @@
  public:
   explicit FeedStream(const base::android::JavaRef<jobject>& j_this,
                       jint stream_kind,
+                      std::string web_feed_id,
                       FeedReliabilityLoggingBridge* reliability_logging_bridge);
   FeedStream(const FeedStream&) = delete;
   FeedStream& operator=(const FeedStream&) = delete;
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStream.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStream.java
index 83d0b4f..c61f247 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStream.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStream.java
@@ -1338,6 +1338,8 @@
     public interface Natives {
         long init(FeedStream caller, @StreamKind int streamKind,
                 long nativeFeedReliabilityLoggingBridge);
+        long initWebFeed(
+                FeedStream caller, byte[] webFeedId, long nativeFeedReliabilityLoggingBridge);
         void reportFeedViewed(long nativeFeedStream, FeedStream caller);
         void reportSliceViewed(long nativeFeedStream, FeedStream caller, String sliceId);
         void reportPageLoaded(long nativeFeedStream, FeedStream caller, boolean inNewTab);
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 1b29593..e142c81 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1655,6 +1655,11 @@
     "expiry_milestone": 99
   },
   {
+    "name": "enable-16-desks",
+    "owners": [ "dandersson", "janetmac" ],
+    "expiry_milestone": 118
+  },
+  {
     "name": "enable-accelerated-video-decode",
     "owners": [ "media-dev@chromium.org" ],
     "expiry_milestone": 93
@@ -6871,7 +6876,12 @@
   },
   {
     "name": "vc-background-blur",
-    "owners": [ "shafron", "skyostil", "charleszhao" ],
+    "owners": [ "shafron", "skyostil", "charleszhao", "jmpollock" ],
+    "expiry_milestone": 115
+  },
+  {
+    "name": "vc-background-replace",
+    "owners": [ "shafron", "skyostil", "charleszhao", "jmpollock" ],
     "expiry_milestone": 115
   },
   {
@@ -6880,6 +6890,11 @@
     "expiry_milestone": 117
   },
   {
+    "name": "vc-portrait-relighting",
+    "owners": [ "shafron", "skyostil", "charleszhao", "jmpollock" ],
+    "expiry_milestone": 115
+  },
+  {
     "name": "verbose-logging-in-nacl",
     "owners": [ "fabiansommer", "native-client-dev@googlegroups.com" ],
     // This flag is useful for debugging NaCl-related issues.
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 9531085..eba4e404 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -3105,6 +3105,16 @@
 const char kVCBackgroundBlurDescription[] =
     "Enables background blur feature for video conferencing on chromebooks.";
 
+const char kVCBackgroundReplaceName[] = "Enable vc background replacement";
+const char kVCBackgroundReplaceDescription[] =
+    "Enables background replacement feature for video conferencing on "
+    "chromebooks. THIS WILL OVERRIDE BACKGROUND BLUR.";
+
+const char kVCPortraitRelightingName[] = "Enable vc portrait relighting";
+const char kVCPortraitRelightingDescription[] =
+    "Enables portrait relighting feature for video conferencing on "
+    "chromebooks. THIS WILL OVERRIDE BACKGROUND BLUR & REPLACE.";
+
 const char kV8VmFutureName[] = "Future V8 VM features";
 const char kV8VmFutureDescription[] =
     "This enables upcoming and experimental V8 VM features. "
@@ -4993,6 +5003,10 @@
     "When enabled, newly installed apps will not capture links clicked in the "
     "browser.";
 
+extern const char kDesks16Name[] = "Enable up to 16 virtual desks";
+extern const char kDesks16Description[] =
+    "When enabled, up to 16 virtual desks are allowed.";
+
 const char kDesksCloseAllName[] = "Desks Close All";
 const char kDesksCloseAllDescription[] =
     "Close a desk along with all of its windows and tabs.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index ed09cb1..a5ffbaa 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1742,6 +1742,12 @@
 extern const char kVCBackgroundBlurName[];
 extern const char kVCBackgroundBlurDescription[];
 
+extern const char kVCBackgroundReplaceName[];
+extern const char kVCBackgroundReplaceDescription[];
+
+extern const char kVCPortraitRelightingName[];
+extern const char kVCPortraitRelightingDescription[];
+
 extern const char kV8VmFutureName[];
 extern const char kV8VmFutureDescription[];
 
@@ -2851,6 +2857,9 @@
 extern const char kDefaultLinkCapturingInBrowserName[];
 extern const char kDefaultLinkCapturingInBrowserDescription[];
 
+extern const char kDesks16Name[];
+extern const char kDesks16Description[];
+
 extern const char kDesksCloseAllName[];
 extern const char kDesksCloseAllDescription[];
 
diff --git a/chrome/browser/metrics/power/power_metrics_reporter.cc b/chrome/browser/metrics/power/power_metrics_reporter.cc
index d75d065..e59edc8 100644
--- a/chrome/browser/metrics/power/power_metrics_reporter.cc
+++ b/chrome/browser/metrics/power/power_metrics_reporter.cc
@@ -67,12 +67,12 @@
       return "RendererExtensionEventProcess";
     case MonitoredProcessType::kGpu:
       return "GPUProcess";
-    case MonitoredProcessType::kPPAPIPlugin:
-      return "PPAPIProcess";
     case MonitoredProcessType::kUtility:
       return "UtilityProcess";
     case MonitoredProcessType::kNetwork:
       return "NetworkProcess";
+    case MonitoredProcessType::kOther:
+      return "OtherProcess";
     default:
       NOTREACHED();
       return "";
diff --git a/chrome/browser/metrics/power/power_metrics_reporter_unittest.cc b/chrome/browser/metrics/power/power_metrics_reporter_unittest.cc
index 855f851e..5af7f86 100644
--- a/chrome/browser/metrics/power/power_metrics_reporter_unittest.cc
+++ b/chrome/browser/metrics/power/power_metrics_reporter_unittest.cc
@@ -262,12 +262,12 @@
   task_environment_.FastForwardBy(kLongPowerMetricsIntervalDuration);
 
 // Windows ARM64 does not support Constant Rate TSC so
-// PerformanceMonitor.AverageCPU7.Total is not recorded there.
+// PerformanceMonitor.AverageCPU8.Total is not recorded there.
 #if !BUILDFLAG(IS_WIN) || !defined(ARCH_CPU_ARM64)
   const char* kScenarioSuffix = ".VideoCapture";
   const std::vector<const char*> suffixes({"", kScenarioSuffix});
   ExpectHistogramSamples(&histogram_tester_, suffixes,
-                         {{"PerformanceMonitor.AverageCPU7.Total", 500}});
+                         {{"PerformanceMonitor.AverageCPU8.Total", 500}});
 #endif
 }
 
@@ -284,12 +284,12 @@
   task_environment_.FastForwardBy(kLongPowerMetricsIntervalDuration);
 
 // Windows ARM64 does not support Constant Rate TSC so
-// PerformanceMonitor.AverageCPU7.Total is not recorded there.
+// PerformanceMonitor.AverageCPU8.Total is not recorded there.
 #if !BUILDFLAG(IS_WIN) || !defined(ARCH_CPU_ARM64)
   const char* kScenarioSuffix = ".VideoCapture";
   const std::vector<const char*> suffixes({"", kScenarioSuffix});
   ExpectHistogramSamples(&histogram_tester_, suffixes,
-                         {{"PerformanceMonitor.AverageCPU7.Total", 500}});
+                         {{"PerformanceMonitor.AverageCPU8.Total", 500}});
 #endif
 }
 
diff --git a/chrome/browser/metrics/power/power_metrics_unittest.cc b/chrome/browser/metrics/power/power_metrics_unittest.cc
index a09da39..d6b9074 100644
--- a/chrome/browser/metrics/power/power_metrics_unittest.cc
+++ b/chrome/browser/metrics/power/power_metrics_unittest.cc
@@ -86,9 +86,9 @@
 
   ExpectHistogramSamples(&histogram_tester, suffixes, {
 // Windows ARM64 does not support Constant Rate TSC so
-// PerformanceMonitor.AverageCPU7.Total is not recorded there.
+// PerformanceMonitor.AverageCPU8.Total is not recorded there.
 #if !BUILDFLAG(IS_WIN) || !defined(ARCH_CPU_ARM64)
-    {"PerformanceMonitor.AverageCPU7.Total", 20},
+    {"PerformanceMonitor.AverageCPU8.Total", 20},
 #endif
 
 #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
diff --git a/chrome/browser/metrics/power/process_metrics_recorder_util.cc b/chrome/browser/metrics/power/process_metrics_recorder_util.cc
index 6ac3e85..f0d540d 100644
--- a/chrome/browser/metrics/power/process_metrics_recorder_util.cc
+++ b/chrome/browser/metrics/power/process_metrics_recorder_util.cc
@@ -48,7 +48,7 @@
 #endif
 
   base::UmaHistogramCustomCounts(
-      base::StrCat({"PerformanceMonitor.AverageCPU7.", histogram_suffix}),
+      base::StrCat({"PerformanceMonitor.AverageCPU8.", histogram_suffix}),
       cpu_usage * kCPUUsageFactor, kCPUUsageHistogramMin, kCPUUsageHistogramMax,
       kCPUUsageHistogramBucketCount);
 }
diff --git a/chrome/browser/metrics/power/process_monitor.cc b/chrome/browser/metrics/power/process_monitor.cc
index b759aeed..9ea5d9a 100644
--- a/chrome/browser/metrics/power/process_monitor.cc
+++ b/chrome/browser/metrics/power/process_monitor.cc
@@ -141,6 +141,27 @@
 #endif
 }
 
+MonitoredProcessType GetMonitoredProcessTypeForNonRendererChildProcess(
+    const content::ChildProcessData& data) {
+  switch (data.process_type) {
+    case content::PROCESS_TYPE_BROWSER:
+    case content::PROCESS_TYPE_RENDERER:
+      // Not a non-renderer child process.
+      NOTREACHED();
+      return kCount;
+    case content::PROCESS_TYPE_GPU:
+      return MonitoredProcessType::kGpu;
+    case content::PROCESS_TYPE_UTILITY: {
+      // Special case for the network process.
+      if (data.metrics_name == network::mojom::NetworkService::Name_)
+        return MonitoredProcessType::kNetwork;
+      return MonitoredProcessType::kUtility;
+    }
+    default:
+      return MonitoredProcessType::kOther;
+  }
+}
+
 // Adds the values from |rhs| to |lhs|.
 ProcessMonitor::Metrics& operator+=(ProcessMonitor::Metrics& lhs,
                                     const ProcessMonitor::Metrics& rhs) {
@@ -161,6 +182,12 @@
 
 }  // namespace
 
+MonitoredProcessType
+GetMonitoredProcessTypeForNonRendererChildProcessForTesting(
+    const content::ChildProcessData& data) {
+  return GetMonitoredProcessTypeForNonRendererChildProcess(data);
+}
+
 ProcessInfo::ProcessInfo(MonitoredProcessType type,
                          std::unique_ptr<base::ProcessMetrics> process_metrics)
     : type(type),
@@ -319,9 +346,7 @@
 #endif
 
   MonitoredProcessType type =
-      data.metrics_name == network::mojom::NetworkService::Name_
-          ? MonitoredProcessType::kNetwork
-          : MonitoredProcessType::kUtility;
+      GetMonitoredProcessTypeForNonRendererChildProcess(data);
   bool inserted =
       browser_child_process_infos_
           .emplace(std::piecewise_construct, std::forward_as_tuple(data.id),
diff --git a/chrome/browser/metrics/power/process_monitor.h b/chrome/browser/metrics/power/process_monitor.h
index f4b3875..a9a5c6a 100644
--- a/chrome/browser/metrics/power/process_monitor.h
+++ b/chrome/browser/metrics/power/process_monitor.h
@@ -30,12 +30,16 @@
   kExtensionPersistent,
   kExtensionEvent,
   kGpu,
-  kPPAPIPlugin,
   kUtility,
   kNetwork,
+  kOther,  // Contains all other process types that are not explicitly tracked.
   kCount,
 };
 
+MonitoredProcessType
+GetMonitoredProcessTypeForNonRendererChildProcessForTesting(
+    const content::ChildProcessData& data);
+
 struct ProcessInfo {
   ProcessInfo(MonitoredProcessType type,
               std::unique_ptr<base::ProcessMetrics> process_metrics);
diff --git a/chrome/browser/metrics/power/process_monitor_unittest.cc b/chrome/browser/metrics/power/process_monitor_unittest.cc
new file mode 100644
index 0000000..c3772af
--- /dev/null
+++ b/chrome/browser/metrics/power/process_monitor_unittest.cc
@@ -0,0 +1,32 @@
+// Copyright 2012 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/metrics/power/process_monitor.h"
+
+#include <utility>
+
+#include "content/public/browser/child_process_data.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "services/network/public/mojom/network_service.mojom.h"
+TEST(ProcessMonitorTest, MonitoredProcessType) {
+  const std::pair<int, MonitoredProcessType> kExpectations[] = {
+      {content::PROCESS_TYPE_GPU, MonitoredProcessType::kGpu},
+      {content::PROCESS_TYPE_UTILITY, MonitoredProcessType::kUtility},
+      {content::PROCESS_TYPE_ZYGOTE, MonitoredProcessType::kOther},
+  };
+
+  for (const auto& [process_type, expectation] : kExpectations) {
+    content::ChildProcessData data(process_type);
+    // data.process_type = process_type;
+    EXPECT_EQ(GetMonitoredProcessTypeForNonRendererChildProcessForTesting(data),
+              expectation);
+  }
+
+  // Special case for network process.
+  content::ChildProcessData data(content::PROCESS_TYPE_UTILITY);
+  data.metrics_name = network::mojom::NetworkService::Name_;
+  EXPECT_EQ(GetMonitoredProcessTypeForNonRendererChildProcessForTesting(data),
+            MonitoredProcessType::kNetwork);
+}
diff --git a/chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.cc b/chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.cc
index 519e1bc..12a534f 100644
--- a/chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.cc
+++ b/chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/base64url.h"
+#include "base/command_line.h"
 #include "base/containers/contains.h"
 #include "base/json/values_util.h"
 #include "base/rand_util.h"
@@ -14,6 +15,7 @@
 #include "base/strings/string_piece.h"
 #include "chrome/browser/nearby_sharing/certificates/common.h"
 #include "chrome/browser/nearby_sharing/certificates/constants.h"
+#include "chrome/browser/nearby_sharing/common/nearby_share_switches.h"
 #include "chrome/browser/nearby_sharing/logging/logging.h"
 #include "chrome/browser/nearby_sharing/proto/timestamp.pb.h"
 #include "crypto/aead.h"
@@ -126,6 +128,31 @@
   return salts;
 }
 
+// Check for a command-line override the certificate validity period, otherwise
+// return the default |kNearbyShareCertificateValidityPeriod|.
+base::TimeDelta GetCertificateValidityPeriod() {
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  if (!command_line->HasSwitch(
+          switches::kNearbyShareCertificateValidityPeriodHours)) {
+    return kNearbyShareCertificateValidityPeriod;
+  }
+
+  std::string certificate_validity_period_hours_str =
+      command_line->GetSwitchValueASCII(
+          switches::kNearbyShareCertificateValidityPeriodHours);
+  int certificate_validity_period_hours = 0;
+  if (!base::StringToInt(certificate_validity_period_hours_str,
+                         &certificate_validity_period_hours) ||
+      certificate_validity_period_hours < 1) {
+    NS_LOG(ERROR)
+        << __func__
+        << ": Invalid value provided for certificate validity period override.";
+    return kNearbyShareCertificateValidityPeriod;
+  }
+
+  return base::Hours(certificate_validity_period_hours);
+}
+
 }  // namespace
 
 NearbySharePrivateCertificate::NearbySharePrivateCertificate(
@@ -134,7 +161,7 @@
     nearbyshare::proto::EncryptedMetadata unencrypted_metadata)
     : visibility_(visibility),
       not_before_(not_before),
-      not_after_(not_before_ + kNearbyShareCertificateValidityPeriod),
+      not_after_(not_before_ + GetCertificateValidityPeriod()),
       key_pair_(crypto::ECPrivateKey::Create()),
       secret_key_(crypto::SymmetricKey::GenerateRandomKey(
           crypto::SymmetricKey::Algorithm::AES,
diff --git a/chrome/browser/nearby_sharing/common/nearby_share_switches.cc b/chrome/browser/nearby_sharing/common/nearby_share_switches.cc
index a84890d..3aa3303 100644
--- a/chrome/browser/nearby_sharing/common/nearby_share_switches.cc
+++ b/chrome/browser/nearby_sharing/common/nearby_share_switches.cc
@@ -6,6 +6,11 @@
 
 namespace switches {
 
+// Overrides the default validity period for Nearby Share certificates. Value
+// must be larger than 0.
+const char kNearbyShareCertificateValidityPeriodHours[] =
+    "nearby-share-certificate-validity-period-hours";
+
 // Overrides the default URL for Google APIs (https://www.googleapis.com) used
 // by Nearby Share
 const char kNearbyShareHTTPHost[] = "nearbysharing-http-host";
diff --git a/chrome/browser/nearby_sharing/common/nearby_share_switches.h b/chrome/browser/nearby_sharing/common/nearby_share_switches.h
index 7d3bc46..4a6cc770 100644
--- a/chrome/browser/nearby_sharing/common/nearby_share_switches.h
+++ b/chrome/browser/nearby_sharing/common/nearby_share_switches.h
@@ -9,6 +9,7 @@
 
 // All switches in alphabetical order. The switches should be documented
 // alongside the definition of their values in the .cc file.
+extern const char kNearbyShareCertificateValidityPeriodHours[];
 extern const char kNearbyShareHTTPHost[];
 extern const char kNearbyShareNumPrivateCertificates[];
 extern const char kNearbyShareVerboseLogging[];
diff --git a/chrome/browser/platform_keys/platform_keys.cc b/chrome/browser/platform_keys/platform_keys.cc
index 39fff64..449ca3cc 100644
--- a/chrome/browser/platform_keys/platform_keys.cc
+++ b/chrome/browser/platform_keys/platform_keys.cc
@@ -417,7 +417,7 @@
     return output;
   }
 
-  absl::optional<base::DictionaryValue> algorithm =
+  absl::optional<base::Value::Dict> algorithm =
       BuildWebCrypAlgorithmDictionary(key_info);
   DCHECK(algorithm.has_value());
   output.algorithm = std::move(algorithm.value());
@@ -465,16 +465,16 @@
   return net::X509Certificate::kPublicKeyTypeUnknown;
 }
 
-absl::optional<base::DictionaryValue> BuildWebCrypAlgorithmDictionary(
+absl::optional<base::Value::Dict> BuildWebCrypAlgorithmDictionary(
     const PublicKeyInfo& key_info) {
   switch (key_info.key_type) {
     case net::X509Certificate::kPublicKeyTypeRSA: {
-      base::DictionaryValue result;
+      base::Value::Dict result;
       BuildWebCryptoRSAAlgorithmDictionary(key_info, &result);
       return result;
     }
     case net::X509Certificate::kPublicKeyTypeECDSA: {
-      base::DictionaryValue result;
+      base::Value::Dict result;
       BuildWebCryptoEcdsaAlgorithmDictionary(key_info, &result);
       return result;
     }
@@ -484,25 +484,25 @@
 }
 
 void BuildWebCryptoRSAAlgorithmDictionary(const PublicKeyInfo& key_info,
-                                          base::DictionaryValue* algorithm) {
+                                          base::Value::Dict* algorithm) {
   CHECK_EQ(net::X509Certificate::kPublicKeyTypeRSA, key_info.key_type);
-  algorithm->SetStringKey("name", kWebCryptoRsassaPkcs1v15);
-  algorithm->SetKey("modulusLength",
-                    base::Value(static_cast<int>(key_info.key_size_bits)));
+  algorithm->Set("name", kWebCryptoRsassaPkcs1v15);
+  algorithm->Set("modulusLength", static_cast<int>(key_info.key_size_bits));
 
   // Equals 65537.
   static constexpr uint8_t kDefaultPublicExponent[] = {0x01, 0x00, 0x01};
-  algorithm->SetKey("publicExponent",
-                    base::Value(base::make_span(kDefaultPublicExponent)));
+  algorithm->Set("publicExponent",
+                 base::Value::BlobStorage(std::begin(kDefaultPublicExponent),
+                                          std::end(kDefaultPublicExponent)));
 }
 
 void BuildWebCryptoEcdsaAlgorithmDictionary(const PublicKeyInfo& key_info,
-                                            base::DictionaryValue* algorithm) {
+                                            base::Value::Dict* algorithm) {
   CHECK_EQ(net::X509Certificate::kPublicKeyTypeECDSA, key_info.key_type);
-  algorithm->SetStringKey("name", kWebCryptoEcdsa);
+  algorithm->Set("name", kWebCryptoEcdsa);
 
   // Only P-256 named curve is supported.
-  algorithm->SetStringKey("namedCurve", kWebCryptoNamedCurveP256);
+  algorithm->Set("namedCurve", kWebCryptoNamedCurveP256);
 }
 
 ClientCertificateRequest::ClientCertificateRequest() = default;
diff --git a/chrome/browser/platform_keys/platform_keys.h b/chrome/browser/platform_keys/platform_keys.h
index ffd9c6c..48a531a 100644
--- a/chrome/browser/platform_keys/platform_keys.h
+++ b/chrome/browser/platform_keys/platform_keys.h
@@ -103,7 +103,7 @@
 
   Status status = Status::kSuccess;
   std::vector<uint8_t> public_key;  // Only set if status == kSuccess
-  base::DictionaryValue algorithm;  // Only set if status == kSuccess
+  base::Value::Dict algorithm;      // Only set if status == kSuccess
 };
 
 // This is a convenient wrapper around GetPublicKey which also builds a
@@ -145,7 +145,7 @@
 // |key_info|. This supports both RSA and EC keys.
 // Returns absl::nullopt if the key is of an unsupported type (so not RSA or
 // EC).
-absl::optional<base::DictionaryValue> BuildWebCrypAlgorithmDictionary(
+absl::optional<base::Value::Dict> BuildWebCrypAlgorithmDictionary(
     const PublicKeyInfo& key_info);
 
 // Builds a partial WebCrypto Algorithm object from the parameters available in
@@ -153,14 +153,14 @@
 // sign/hash parameters and thus isn't complete. platform_keys::GetPublicKey()
 // enforced the public exponent 65537.
 void BuildWebCryptoRSAAlgorithmDictionary(const PublicKeyInfo& key_info,
-                                          base::DictionaryValue* algorithm);
+                                          base::Value::Dict* algorithm);
 
 // Builds a partial WebCrypto Algorithm object from the parameters available in
 // |key_info|, which must be the info of an EC key. For more information about
 // EcKeyAlgorithm dictionary, please refer to:
 // https://www.w3.org/TR/WebCryptoAPI/#EcKeyAlgorithm-dictionary
 void BuildWebCryptoEcdsaAlgorithmDictionary(const PublicKeyInfo& key_info,
-                                            base::DictionaryValue* algorithm);
+                                            base::Value::Dict* algorithm);
 
 // Obtains information about the public key in |certificate|.
 // If |certificate| contains an RSA key, sets |key_size_bits| to the modulus
diff --git a/chrome/browser/preloading/chrome_preloading.h b/chrome/browser/preloading/chrome_preloading.h
index 16126d8..760b41f 100644
--- a/chrome/browser/preloading/chrome_preloading.h
+++ b/chrome/browser/preloading/chrome_preloading.h
@@ -47,6 +47,11 @@
   kOmniboxSearchPredictor =
       static_cast<int>(PreloadingPredictor::kPreloadingPredictorContentEnd) + 3,
 
+  // When the preloading URL is predicted from the default search suggest due to
+  // mouse being pressed down on a Omnibox Search suggestion.
+  kOmniboxMousePredictor =
+      static_cast<int>(PreloadingPredictor::kPreloadingPredictorContentEnd) + 4,
+
   // TODO(crbug.com/1309934): Integrate more Preloading predictors with
   // Preloading logging APIs.
 };
diff --git a/chrome/browser/preloading/prefetch/no_state_prefetch/prerender_nostate_prefetch_browsertest.cc b/chrome/browser/preloading/prefetch/no_state_prefetch/prerender_nostate_prefetch_browsertest.cc
index fb86289..116e4c6 100644
--- a/chrome/browser/preloading/prefetch/no_state_prefetch/prerender_nostate_prefetch_browsertest.cc
+++ b/chrome/browser/preloading/prefetch/no_state_prefetch/prerender_nostate_prefetch_browsertest.cc
@@ -442,7 +442,8 @@
     if (split_cache_by_network_isolation_key) {
       feature_list_.InitWithFeatures(
           {net::features::kSplitCacheByNetworkIsolationKey},
-          {net::features::kForceIsolationInfoFrameOriginToTopLevelFrame});
+          {net::features::kForceIsolationInfoFrameOriginToTopLevelFrame,
+           net::features::kEnableDoubleKeyNetworkAnonymizationKey});
     } else {
       feature_list_.InitAndDisableFeature(
           net::features::kSplitCacheByNetworkIsolationKey);
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/field_trial_settings.cc b/chrome/browser/preloading/prefetch/search_prefetch/field_trial_settings.cc
index 7857eff7..278d7ae 100644
--- a/chrome/browser/preloading/prefetch/search_prefetch/field_trial_settings.cc
+++ b/chrome/browser/preloading/prefetch/search_prefetch/field_trial_settings.cc
@@ -74,3 +74,23 @@
 bool SearchPrefetchSkipsCancel() {
   return base::FeatureList::IsEnabled(kSearchPrefetchSkipsCancel);
 }
+
+bool IsUpOrDownArrowPrefetchEnabled() {
+  return base::GetFieldTrialParamByFeatureAsBool(kSearchNavigationPrefetch,
+                                                 "up_or_down_arrow", true);
+}
+
+bool IsSearchMouseDownPrefetchEnabled() {
+  return base::GetFieldTrialParamByFeatureAsBool(kSearchNavigationPrefetch,
+                                                 "mouse_down", true);
+}
+
+bool AllowTopNavigationPrefetch() {
+  return base::GetFieldTrialParamByFeatureAsBool(kSearchNavigationPrefetch,
+                                                 "allow_top_selection", true);
+}
+
+bool PrefetchSearchHistorySuggestions() {
+  return base::GetFieldTrialParamByFeatureAsBool(
+      kSearchNavigationPrefetch, "prefetch_search_history", true);
+}
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/field_trial_settings.h b/chrome/browser/preloading/prefetch/search_prefetch/field_trial_settings.h
index b8b423c..da171ab2 100644
--- a/chrome/browser/preloading/prefetch/search_prefetch/field_trial_settings.h
+++ b/chrome/browser/preloading/prefetch/search_prefetch/field_trial_settings.h
@@ -42,12 +42,27 @@
 
 BASE_DECLARE_FEATURE(kSearchNavigationPrefetch);
 
-// An experimental feature to measure if starting search prefetches at
-// navigation start provides benefit over the typical navigation flow.
+// An experimental feature to measure if starting search prefetches during
+// navigation events provides benefit over the typical navigation flow.
 bool IsSearchNavigationPrefetchEnabled();
 
 // An experimental feature that skips the cancellation logic in search prefetch
 // service.
 bool SearchPrefetchSkipsCancel();
 
+// A flavor of navigation prefetch that triggers when the user changes the
+// selected index in omnibox to a search suggestion via arrow buttons.
+bool IsUpOrDownArrowPrefetchEnabled();
+
+// A flavor of navigation prefetch that triggers when the user pushes the mouse
+// down on a Search suggestion.
+bool IsSearchMouseDownPrefetchEnabled();
+
+// Allows the top selection to be prefetched by navigation prefetch strategies.
+bool AllowTopNavigationPrefetch();
+
+// Allows search history suggestions to be prefetched by navigation prefetch
+// strategies.
+bool PrefetchSearchHistorySuggestions();
+
 #endif  // CHROME_BROWSER_PRELOADING_PREFETCH_SEARCH_PREFETCH_FIELD_TRIAL_SETTINGS_H_
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_browser_test_base.cc b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_browser_test_base.cc
index b577175..3978b570 100644
--- a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_browser_test_base.cc
+++ b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_browser_test_base.cc
@@ -433,3 +433,18 @@
 
 SearchPrefetchBaseBrowserTest::SearchSuggestionTuple::SearchSuggestionTuple(
     const SearchSuggestionTuple& other) = default;
+
+AutocompleteMatch SearchPrefetchBaseBrowserTest::CreateSearchSuggestionMatch(
+    const std::string& original_query,
+    const std::string& search_terms,
+    bool prefetch_hint) {
+  AutocompleteMatch match;
+  match.search_terms_args = std::make_unique<TemplateURLRef::SearchTermsArgs>(
+      base::UTF8ToUTF16(search_terms));
+  match.search_terms_args->original_query = base::UTF8ToUTF16(original_query);
+  match.destination_url = GetSearchServerQueryURL(search_terms);
+  match.keyword = base::UTF8ToUTF16(original_query);
+  if (prefetch_hint)
+    match.RecordAdditionalInfo("should_prefetch", "true");
+  return match;
+}
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_browser_test_base.h b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_browser_test_base.h
index 2f98459..6884fc85 100644
--- a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_browser_test_base.h
+++ b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_browser_test_base.h
@@ -16,6 +16,7 @@
 #include "base/memory/raw_ptr.h"
 #include "chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_request.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "components/omnibox/browser/autocomplete_match.h"
 #include "content/public/test/content_mock_cert_verifier.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
@@ -103,6 +104,13 @@
     delayed_response_ = delayed_response;
   }
 
+  // Create a search suggestion match with a prefetch signal when
+  // |prefetch_hint| is true.
+  AutocompleteMatch CreateSearchSuggestionMatch(
+      const std::string& original_query,
+      const std::string& search_terms,
+      bool prefetch_hint);
+
  private:
   std::unique_ptr<net::test_server::HttpResponse> HandleSearchRequest(
       const net::test_server::HttpRequest& request);
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.cc b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.cc
index 230ba3e6..ac905e4 100644
--- a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.cc
+++ b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.cc
@@ -44,17 +44,20 @@
 #include "ui/base/page_transition_types.h"
 #include "url/origin.h"
 
+using omnibox::mojom::NavigationPredictor;
+
 namespace {
 
 // Recomputes the destination URL for |match| with the updated prefetch
 // information (does not modify |destination_url|). Passing true to
 // |attach_prefetch_information| if the URL request will be sent to network,
 // otherwise set to false if it is for client-internal use only.
-GURL GetPreloadURLFromMatch(const AutocompleteMatch& match,
-                            TemplateURLService* template_url_service,
-                            bool attach_prefetch_information) {
+GURL GetPreloadURLFromMatch(
+    const TemplateURLRef::SearchTermsArgs& search_terms_args_from_match,
+    TemplateURLService* template_url_service,
+    bool attach_prefetch_information) {
   // Copy the search term args, so we can modify them for just the prefetch.
-  auto search_terms_args = *(match.search_terms_args);
+  auto search_terms_args = search_terms_args_from_match;
   search_terms_args.is_prefetch = attach_prefetch_information;
   return GURL(template_url_service->GetDefaultSearchProvider()
                   ->url_ref()
@@ -192,13 +195,15 @@
 bool SearchPrefetchService::MaybePrefetchURL(
     const GURL& url,
     content::WebContents* web_contents) {
-  return MaybePrefetchURL(url, /*navigation_prefetch=*/false, web_contents);
+  return MaybePrefetchURL(url, /*navigation_prefetch=*/false, web_contents,
+                          ChromePreloadingPredictor::kDefaultSearchEngine);
 }
 
 bool SearchPrefetchService::MaybePrefetchURL(
     const GURL& url,
     bool navigation_prefetch,
-    content::WebContents* web_contents) {
+    content::WebContents* web_contents,
+    ChromePreloadingPredictor predictor) {
   if (!SearchPrefetchServicePrefetchingIsEnabled())
     return false;
 
@@ -238,11 +243,9 @@
   // Create new PreloadingAttempt and pass all the values corresponding to
   // this DefaultSearchEngine or OmniboxSearchPredictor prefetch attempt when
   // |navigation_prefetch| is true.
-  content::PreloadingPredictor predictor = ToPreloadingPredictor(
-      navigation_prefetch ? ChromePreloadingPredictor::kOmniboxSearchPredictor
-                          : ChromePreloadingPredictor::kDefaultSearchEngine);
   attempt = preloading_data->AddPreloadingAttempt(
-      predictor, content::PreloadingType::kPrefetch, same_url_matcher);
+      ToPreloadingPredictor(predictor), content::PreloadingType::kPrefetch,
+      same_url_matcher);
 
   if (search_terms.size() == 0) {
     recorder.reason_ =
@@ -662,7 +665,7 @@
 
     if (BaseSearchProvider::ShouldPrefetch(match)) {
       MaybePrefetchURL(
-          GetPreloadURLFromMatch(match, template_url_service,
+          GetPreloadURLFromMatch(*match.search_terms_args, template_url_service,
                                  /*attach_prefetch_information=*/true),
           web_contents);
     }
@@ -676,24 +679,37 @@
   }
 }
 
-void SearchPrefetchService::MaybePrefetchLikelyMatch(
+void SearchPrefetchService::OnNavigationLikely(
     size_t index,
     const AutocompleteMatch& match,
+    NavigationPredictor navigation_predictor,
     content::WebContents* web_contents) {
   if (!IsSearchNavigationPrefetchEnabled())
     return;
+
+  auto is_type_allowed = [](NavigationPredictor navigation_predictor) {
+    switch (navigation_predictor) {
+      case NavigationPredictor::kMouseDown:
+        return IsSearchMouseDownPrefetchEnabled();
+      case NavigationPredictor::kUpOrDownArrowButton:
+        return IsUpOrDownArrowPrefetchEnabled();
+    }
+  };
+
+  if (!is_type_allowed(navigation_predictor)) {
+    return;
+  }
+
   if (!web_contents)
     return;
-  // Assume the user is going back to enter more for now.
-  if (index == 0)
+  if (!AllowTopNavigationPrefetch() && index == 0)
     return;
   // Only prefetch search types.
   if (!AutocompleteMatch::IsSearchType(match.type))
     return;
   // Check to make sure this is search related and that we can read the search
   // arguments. For Search history this may be null.
-  if (!match.search_terms_args)
-    return;
+
   auto* template_url_service =
       TemplateURLServiceFactory::GetForProfile(profile_);
   // The default search provider needs to opt into prefetching behavior.
@@ -705,13 +721,34 @@
     return;
   }
 
-  GURL preload_url =
-      GetPreloadURLFromMatch(match, template_url_service,
-                             /*attach_prefetch_information=*/true);
-
+  // Parse the search terms from the match URL to verify this is a valid search
+  // query.
   std::u16string search_terms;
   template_url_service->GetDefaultSearchProvider()->ExtractSearchTermsFromURL(
-      preload_url, template_url_service->search_terms_data(), &search_terms);
+      match.destination_url, template_url_service->search_terms_data(),
+      &search_terms);
+
+  if (search_terms.size() == 0)
+    return;
+
+  // Search history suggestions (those that are not also server suggestions)
+  // don't have search term args. If search history suggestions are enabled,
+  // generate search term args to get a prefetch URL.
+  TemplateURLRef::SearchTermsArgs* search_terms_args_for_prefetch;
+  std::unique_ptr<TemplateURLRef::SearchTermsArgs> search_terms_args;
+  if (!match.search_terms_args) {
+    if (!PrefetchSearchHistorySuggestions())
+      return;
+    search_terms_args =
+        std::make_unique<TemplateURLRef::SearchTermsArgs>(search_terms);
+    search_terms_args_for_prefetch = search_terms_args.get();
+  } else {
+    search_terms_args_for_prefetch = match.search_terms_args.get();
+  }
+
+  GURL preload_url = GetPreloadURLFromMatch(
+      *search_terms_args_for_prefetch, template_url_service,
+      /*attach_prefetch_information=*/true);
 
   content::PreloadingURLMatchCallback same_url_matcher =
       base::BindRepeating(&IsSearchDestinationMatch, search_terms,
@@ -719,13 +756,23 @@
   auto* preloading_data =
       content::PreloadingData::GetOrCreateForWebContents(web_contents);
 
+  auto navigation_likely_event_to_predictor =
+      [](NavigationPredictor navigation_predictor) {
+        switch (navigation_predictor) {
+          case NavigationPredictor::kMouseDown:
+            return ChromePreloadingPredictor::kOmniboxMousePredictor;
+          case NavigationPredictor::kUpOrDownArrowButton:
+            return ChromePreloadingPredictor::kOmniboxSearchPredictor;
+        }
+      };
+  auto predictor = navigation_likely_event_to_predictor(navigation_predictor);
+
   // Create PreloadingPrediction for this match. We set the confidence to 100 as
   // when the user changed the selected match, we always trigger prefetch.
-  preloading_data->AddPreloadingPrediction(
-      ToPreloadingPredictor(ChromePreloadingPredictor::kOmniboxSearchPredictor),
-      100, std::move(same_url_matcher));
+  preloading_data->AddPreloadingPrediction(ToPreloadingPredictor(predictor),
+                                           100, std::move(same_url_matcher));
   MaybePrefetchURL(preload_url,
-                   /*navigation_prefetch=*/true, web_contents);
+                   /*navigation_prefetch=*/true, web_contents, predictor);
 }
 
 void SearchPrefetchService::OnTemplateURLServiceChanged() {
@@ -912,8 +959,9 @@
     TemplateURLService* template_url_service,
     std::u16string search_terms) {
   DCHECK(web_contents);
-  GURL prefetch_url = GetPreloadURLFromMatch(
-      match, template_url_service, /*attach_prefetch_information=*/true);
+  GURL prefetch_url =
+      GetPreloadURLFromMatch(*match.search_terms_args, template_url_service,
+                             /*attach_prefetch_information=*/true);
   MaybePrefetchURL(prefetch_url, web_contents);
   if (!BaseSearchProvider::ShouldPrerender(match))
     return;
@@ -946,8 +994,9 @@
 
   // Prerender URL need not contain the prefetch information to help servers to
   // recognize prefetch traffic, because it should not send network requests.
-  GURL prerender_url = GetPreloadURLFromMatch(
-      match, template_url_service, /*attach_prefetch_information=*/false);
+  GURL prerender_url =
+      GetPreloadURLFromMatch(*match.search_terms_args, template_url_service,
+                             /*attach_prefetch_information=*/false);
   prefetch_request_iter->second->MaybeStartPrerenderSearchResult(
       *prerender_manager, prerender_url, *preloading_attempt);
 }
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.h b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.h
index 1174293..f9ee8a5c 100644
--- a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.h
+++ b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.h
@@ -16,9 +16,11 @@
 #include "base/scoped_observation.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
+#include "chrome/browser/preloading/chrome_preloading.h"
 #include "chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_request.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/omnibox/browser/autocomplete_match.h"
+#include "components/omnibox/browser/omnibox.mojom-shared.h"
 #include "components/search_engines/template_url_data.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/search_engines/template_url_service_observer.h"
@@ -183,9 +185,13 @@
   // for |match|. |index| is the location within the omnibox drop down.
   // |web_contents| represents the active WebContents this prefetch is started
   // which can be nullptr in case no active WebContents is present.
-  void MaybePrefetchLikelyMatch(size_t index,
-                                const AutocompleteMatch& match,
-                                content::WebContents* web_contents);
+  // |navigation_predictor| indicates the omnibox event type that
+  // indicated a likely navigation.
+  void OnNavigationLikely(
+      size_t index,
+      const AutocompleteMatch& match,
+      omnibox::mojom::NavigationPredictor navigation_predictor,
+      content::WebContents* web_contents);
 
   // If the navigation URL matches with a prefetch that can be served, this
   // function marks that prefetch as clicked to prevent deletion when omnibox
@@ -200,7 +206,8 @@
   // Returns whether the prefetch started or not.
   bool MaybePrefetchURL(const GURL& url,
                         bool navigation_prefetch,
-                        content::WebContents* web_contents);
+                        content::WebContents* web_contents,
+                        ChromePreloadingPredictor predictor);
 
   // Adds |this| as an observer of |template_url_service| if not added already.
   void ObserveTemplateURLService(TemplateURLService* template_url_service);
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_browsertest.cc b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_browsertest.cc
index fb2b778..5b6ea92 100644
--- a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_browsertest.cc
+++ b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_browsertest.cc
@@ -55,6 +55,8 @@
 #include "url/gurl.h"
 #include "url/origin.h"
 
+using omnibox::mojom::NavigationPredictor;
+
 namespace {
 
 constexpr char kOmniboxSuggestPrefetchQuery[] = "porgs";
@@ -3392,24 +3394,18 @@
     SearchPrefetchBaseBrowserTest::SetUpOnMainThread();
     // Initialize PreloadingAttempt for this test suite.
     test_ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>();
-    attempt_entry_builder_ =
-        std::make_unique<content::test::PreloadingAttemptUkmEntryBuilder>(
-            ToPreloadingPredictor(
-                ChromePreloadingPredictor::kOmniboxSearchPredictor));
-    prediction_entry_builder_ =
-        std::make_unique<content::test::PreloadingPredictionUkmEntryBuilder>(
-            ToPreloadingPredictor(
-                ChromePreloadingPredictor::kOmniboxSearchPredictor));
   }
 
-  const content::test::PreloadingAttemptUkmEntryBuilder&
-  attempt_entry_builder() {
-    return *attempt_entry_builder_;
+  std::unique_ptr<content::test::PreloadingAttemptUkmEntryBuilder>
+  attempt_entry_builder(ChromePreloadingPredictor predictor) {
+    return std::make_unique<content::test::PreloadingAttemptUkmEntryBuilder>(
+        ToPreloadingPredictor(predictor));
   }
 
-  const content::test::PreloadingPredictionUkmEntryBuilder&
-  prediction_entry_builder() {
-    return *prediction_entry_builder_;
+  std::unique_ptr<content::test::PreloadingPredictionUkmEntryBuilder>
+  prediction_entry_builder(ChromePreloadingPredictor predictor) {
+    return std::make_unique<content::test::PreloadingPredictionUkmEntryBuilder>(
+        ToPreloadingPredictor(predictor));
   }
 
   ukm::TestAutoSetUkmRecorder* test_ukm_recorder() {
@@ -3419,57 +3415,113 @@
  private:
   base::test::ScopedFeatureList feature_list_;
   std::unique_ptr<ukm::TestAutoSetUkmRecorder> test_ukm_recorder_;
-  std::unique_ptr<content::test::PreloadingAttemptUkmEntryBuilder>
-      attempt_entry_builder_;
-  std::unique_ptr<content::test::PreloadingPredictionUkmEntryBuilder>
-      prediction_entry_builder_;
 };
 
 IN_PROC_BROWSER_TEST_F(SearchPrefetchServiceNavigationPrefetchBrowserTest,
-                       NavigationPrefetchIsServed) {
+                       NavigationPrefetchIsServedMouseDown) {
   SetDSEWithURL(
       GetSearchServerQueryURL("{searchTerms}&{google:prefetchSource}"), true);
   auto* search_prefetch_service =
       SearchPrefetchServiceFactory::GetForProfile(browser()->profile());
   std::string search_terms = "terms of service";
   std::string user_input = "terms";
-  AddNewSuggestionRule(user_input, {user_input, search_terms},
-                       /*prefetch_index=*/-1, /*prerender_index=*/-1);
 
-  // Trigger an omnibox suggest fetch that does not have a prefetch hint.
-  AutocompleteInput input(
-      base::ASCIIToUTF16(user_input), metrics::OmniboxEventProto::BLANK,
-      ChromeAutocompleteSchemeClassifier(browser()->profile()));
-  LocationBar* location_bar = browser()->window()->GetLocationBar();
-  OmniboxView* omnibox = location_bar->GetOmniboxView();
-  AutocompleteController* autocomplete_controller =
-      omnibox->model()->autocomplete_controller();
+  AutocompleteMatch autocomplete_match =
+      CreateSearchSuggestionMatch(search_terms, search_terms, false);
+  SearchPrefetchServiceFactory::GetForProfile(browser()->profile())
+      ->OnNavigationLikely(1, autocomplete_match,
+                           NavigationPredictor::kMouseDown, GetWebContents());
 
-  // Prevent the stop timer from killing the hints fetch early.
-  autocomplete_controller->SetStartStopTimerDurationForTesting(
-      base::Seconds(10));
-  autocomplete_controller->Start(input);
-
-  ui_test_utils::WaitForAutocompleteDone(browser());
-  EXPECT_TRUE(autocomplete_controller->done());
-
-  omnibox->model()->SetPopupSelection(OmniboxPopupSelection(1));
-
+  WaitUntilStatusChangesTo(base::ASCIIToUTF16(search_terms),
+                           SearchPrefetchStatus::kComplete);
   auto prefetch_status =
       search_prefetch_service->GetSearchPrefetchStatusForTesting(
           base::ASCIIToUTF16(search_terms));
   ASSERT_TRUE(prefetch_status.has_value());
-  EXPECT_EQ(SearchPrefetchStatus::kCanBeServed, prefetch_status.value());
+  EXPECT_EQ(SearchPrefetchStatus::kComplete, prefetch_status.value());
 
-  omnibox->model()->AcceptInput(WindowOpenDisposition::CURRENT_TAB);
+  auto [prefetch_url, search_url] =
+      GetSearchPrefetchAndNonPrefetch(search_terms);
+  // Navigate.
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), search_url));
 
   prefetch_status = search_prefetch_service->GetSearchPrefetchStatusForTesting(
       base::ASCIIToUTF16(search_terms));
-  ASSERT_TRUE(prefetch_status.has_value());
-  EXPECT_EQ(SearchPrefetchStatus::kCanBeServedAndUserClicked,
-            prefetch_status.value());
+  EXPECT_FALSE(prefetch_status.has_value());
 
-  content::WaitForLoadStop(GetWebContents());
+  auto inner_html = GetDocumentInnerHTML();
+  EXPECT_FALSE(base::Contains(inner_html, "regular"));
+  EXPECT_TRUE(base::Contains(inner_html, "prefetch"));
+
+  {
+    ukm::SourceId ukm_source_id =
+        GetWebContents()->GetPrimaryMainFrame()->GetPageUkmSourceId();
+    auto attempt_ukm_entries = test_ukm_recorder()->GetEntries(
+        Preloading_Attempt::kEntryName,
+        content::test::kPreloadingAttemptUkmMetrics);
+    auto prediction_ukm_entries = test_ukm_recorder()->GetEntries(
+        Preloading_Prediction::kEntryName,
+        content::test::kPreloadingPredictionUkmMetrics);
+
+    // Check that we store one PreloadingPrediction and PreloadingAttempt for
+    // kOmniboxMousePredictor.
+    EXPECT_EQ(attempt_ukm_entries.size(), 1u);
+    EXPECT_EQ(prediction_ukm_entries.size(), 1u);
+
+    // Check that PreloadingAttempt is successful and accurately triggered.
+    std::vector<UkmEntry> expected_prediction_entries = {
+        prediction_entry_builder(
+            ChromePreloadingPredictor::kOmniboxMousePredictor)
+            ->BuildEntry(ukm_source_id,
+                         /*confidence=*/100,
+                         /*accurate_prediction=*/true)};
+    std::vector<UkmEntry> expected_attempt_entries = {
+        attempt_entry_builder(ChromePreloadingPredictor::kOmniboxMousePredictor)
+            ->BuildEntry(ukm_source_id, content::PreloadingType::kPrefetch,
+                         content::PreloadingEligibility::kEligible,
+                         content::PreloadingHoldbackStatus::kAllowed,
+                         content::PreloadingTriggeringOutcome::kSuccess,
+                         content::PreloadingFailureReason::kUnspecified,
+                         /*accurate=*/true)};
+    EXPECT_THAT(attempt_ukm_entries,
+                testing::UnorderedElementsAreArray(expected_attempt_entries))
+        << content::test::ActualVsExpectedUkmEntriesToString(
+               attempt_ukm_entries, expected_attempt_entries);
+    EXPECT_THAT(prediction_ukm_entries,
+                testing::UnorderedElementsAreArray(expected_prediction_entries))
+        << content::test::ActualVsExpectedUkmEntriesToString(
+               prediction_ukm_entries, expected_attempt_entries);
+  }
+}
+
+IN_PROC_BROWSER_TEST_F(SearchPrefetchServiceNavigationPrefetchBrowserTest,
+                       NavigationPrefetchIsServedArrowDown) {
+  SetDSEWithURL(
+      GetSearchServerQueryURL("{searchTerms}&{google:prefetchSource}"), true);
+  auto* search_prefetch_service =
+      SearchPrefetchServiceFactory::GetForProfile(browser()->profile());
+  std::string search_terms = "terms of service";
+  std::string user_input = "terms";
+
+  AutocompleteMatch autocomplete_match =
+      CreateSearchSuggestionMatch(search_terms, search_terms, false);
+  SearchPrefetchServiceFactory::GetForProfile(browser()->profile())
+      ->OnNavigationLikely(1, autocomplete_match,
+                           NavigationPredictor::kUpOrDownArrowButton,
+                           GetWebContents());
+
+  WaitUntilStatusChangesTo(base::ASCIIToUTF16(search_terms),
+                           SearchPrefetchStatus::kComplete);
+  auto prefetch_status =
+      search_prefetch_service->GetSearchPrefetchStatusForTesting(
+          base::ASCIIToUTF16(search_terms));
+  ASSERT_TRUE(prefetch_status.has_value());
+  EXPECT_EQ(SearchPrefetchStatus::kComplete, prefetch_status.value());
+
+  auto [prefetch_url, search_url] =
+      GetSearchPrefetchAndNonPrefetch(search_terms);
+  // Navigate.
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), search_url));
 
   prefetch_status = search_prefetch_service->GetSearchPrefetchStatusForTesting(
       base::ASCIIToUTF16(search_terms));
@@ -3496,17 +3548,20 @@
 
     // Check that PreloadingAttempt is successful and accurately triggered.
     std::vector<UkmEntry> expected_prediction_entries = {
-        prediction_entry_builder().BuildEntry(ukm_source_id,
-                                              /*confidence=*/100,
-                                              /*accurate_prediction=*/true)};
+        prediction_entry_builder(
+            ChromePreloadingPredictor::kOmniboxSearchPredictor)
+            ->BuildEntry(ukm_source_id,
+                         /*confidence=*/100,
+                         /*accurate_prediction=*/true)};
     std::vector<UkmEntry> expected_attempt_entries = {
-        attempt_entry_builder().BuildEntry(
-            ukm_source_id, content::PreloadingType::kPrefetch,
-            content::PreloadingEligibility::kEligible,
-            content::PreloadingHoldbackStatus::kAllowed,
-            content::PreloadingTriggeringOutcome::kSuccess,
-            content::PreloadingFailureReason::kUnspecified,
-            /*accurate=*/true)};
+        attempt_entry_builder(
+            ChromePreloadingPredictor::kOmniboxSearchPredictor)
+            ->BuildEntry(ukm_source_id, content::PreloadingType::kPrefetch,
+                         content::PreloadingEligibility::kEligible,
+                         content::PreloadingHoldbackStatus::kAllowed,
+                         content::PreloadingTriggeringOutcome::kSuccess,
+                         content::PreloadingFailureReason::kUnspecified,
+                         /*accurate=*/true)};
     EXPECT_THAT(attempt_ukm_entries,
                 testing::UnorderedElementsAreArray(expected_attempt_entries))
         << content::test::ActualVsExpectedUkmEntriesToString(
@@ -3715,29 +3770,18 @@
       GetSearchServerQueryURL("{searchTerms}&{google:prefetchSource}"), true);
   std::string search_terms = "terms of service";
   std::string user_input = "terms";
-  AddNewSuggestionRule(user_input, {user_input, search_terms},
-                       /*prefetch_index=*/-1, /*prerender_index=*/-1);
 
-  // Trigger an omnibox suggest fetch that does not have a prefetch hint.
-  AutocompleteInput input(
-      base::ASCIIToUTF16(user_input), metrics::OmniboxEventProto::BLANK,
-      ChromeAutocompleteSchemeClassifier(browser()->profile()));
-  LocationBar* location_bar = browser()->window()->GetLocationBar();
-  OmniboxView* omnibox = location_bar->GetOmniboxView();
-  AutocompleteController* autocomplete_controller =
-      omnibox->model()->autocomplete_controller();
+  AutocompleteMatch autocomplete_match =
+      CreateSearchSuggestionMatch(search_terms, search_terms, false);
+  SearchPrefetchServiceFactory::GetForProfile(browser()->profile())
+      ->OnNavigationLikely(1, autocomplete_match,
+                           NavigationPredictor::kUpOrDownArrowButton,
+                           GetWebContents());
 
-  // Prevent the stop timer from killing the hints fetch early.
-  autocomplete_controller->SetStartStopTimerDurationForTesting(
-      base::Seconds(10));
-  autocomplete_controller->Start(input);
-
-  ui_test_utils::WaitForAutocompleteDone(browser());
-  EXPECT_TRUE(autocomplete_controller->done());
-
-  omnibox->model()->SetPopupSelection(OmniboxPopupSelection(1));
-  omnibox->model()->AcceptInput(WindowOpenDisposition::CURRENT_TAB);
-  content::WaitForLoadStop(GetWebContents());
+  auto [prefetch_url, search_url] =
+      GetSearchPrefetchAndNonPrefetch(search_terms);
+  // Navigate.
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), search_url));
 
   {
     ukm::SourceId ukm_source_id =
@@ -3805,21 +3849,6 @@
     return *attempt_entry_builder_;
   }
 
-  AutocompleteMatch CreateSearchSuggestionMatch(
-      const std::string& original_query,
-      const std::string& search_terms,
-      bool prefetch_hint) {
-    AutocompleteMatch match;
-    match.search_terms_args = std::make_unique<TemplateURLRef::SearchTermsArgs>(
-        base::UTF8ToUTF16(search_terms));
-    match.search_terms_args->original_query = base::UTF8ToUTF16(original_query);
-    match.destination_url = GetSearchServerQueryURL(search_terms);
-    match.keyword = base::UTF8ToUTF16(original_query);
-    if (prefetch_hint)
-      match.RecordAdditionalInfo("should_prefetch", "true");
-    return match;
-  }
-
  private:
   base::test::ScopedFeatureList feature_list_;
   std::unique_ptr<ukm::TestAutoSetUkmRecorder> test_ukm_recorder_;
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_search.html b/chrome/browser/resources/chromeos/emoji_picker/emoji_search.html
index f08d5ca3..32abc96 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_search.html
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_search.html
@@ -154,7 +154,7 @@
 </style>
 
 <div id="search-shadow">
-  <cr-search-field id="search" label="Search" autofocus="true">
+  <cr-search-field id="search" label="Search Emojis" autofocus="true">
   </cr-search-field>
   <template is="dom-if" if="[[v2Enabled]]">
     <div id="category-button-group">
diff --git a/chrome/browser/resources/chromeos/login/BUILD.gn b/chrome/browser/resources/chromeos/login/BUILD.gn
index 5d4a9f4a..f700873 100644
--- a/chrome/browser/resources/chromeos/login/BUILD.gn
+++ b/chrome/browser/resources/chromeos/login/BUILD.gn
@@ -216,7 +216,6 @@
     "components/oobe_carousel.m.js",
     "components/oobe_slide.m.js",
     "components/oobe_vars/oobe_shared_vars_css.m.js",
-    "components/progress_list_item/progress_list_item.m.js",
     "components/display_manager_types.m.js",
     "components/gaia_dialog.m.js",
     "components/gaia_header.m.js",
@@ -272,6 +271,7 @@
   in_files = [
     "components/gaia_button.js",
     "components/notification_card.js",
+    "components/progress_list_item/progress_list_item.js",
     "components/security_token_pin.js",
     "screens/common/adb_sideloading.js",
     "screens/common/app_downloading.js",
@@ -330,6 +330,7 @@
 group("generate_web_components") {
   public_deps = [
     "components:web_components",
+    "components/progress_list_item:web_components",
     "screens/common:web_components",
     "screens/login:web_components",
     "screens/oobe:web_components",
diff --git a/chrome/browser/resources/chromeos/login/components/BUILD.gn b/chrome/browser/resources/chromeos/login/components/BUILD.gn
index 71dc3b9..08360068 100644
--- a/chrome/browser/resources/chromeos/login/components/BUILD.gn
+++ b/chrome/browser/resources/chromeos/login/components/BUILD.gn
@@ -55,7 +55,6 @@
                   "common_styles:polymer3_elements",
                   "dialogs:polymer3_elements",
                   "oobe_vars:polymer3_elements",
-                  "progress_list_item:polymer3_elements",
 
                   # Local targets
                   ":gaia_dialog_module",
diff --git a/chrome/browser/resources/chromeos/login/components/progress_list_item/BUILD.gn b/chrome/browser/resources/chromeos/login/components/progress_list_item/BUILD.gn
index 8a4f724..ae19a1d 100644
--- a/chrome/browser/resources/chromeos/login/components/progress_list_item/BUILD.gn
+++ b/chrome/browser/resources/chromeos/login/components/progress_list_item/BUILD.gn
@@ -3,33 +3,25 @@
 # found in the LICENSE file.
 
 import("//third_party/closure_compiler/compile_js.gni")
+import("//tools/polymer/html_to_js.gni")
 import("//tools/polymer/polymer.gni")
 import("../../oobe_auto_imports.gni")
 
-group("polymer3_elements") {
-  public_deps = [ ":progress_list_item_module" ]
-}
-
 js_type_check("closure_compile") {
   is_polymer3 = true
   closure_flags = default_closure_args
-  deps = [ ":progress_list_item.m" ]
+  deps = [ ":progress_list_item" ]
 }
 
-js_library("progress_list_item.m") {
-  sources = [ "$root_gen_dir/chrome/browser/resources/chromeos/login/components/progress_list_item/progress_list_item.m.js" ]
+js_library("progress_list_item") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/chromeos/login/components/progress_list_item/progress_list_item.js" ]
   deps = [
     "../../components/behaviors:oobe_i18n_behavior.m",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
   ]
-  extra_deps = [ ":progress_list_item_module" ]
+  extra_deps = [ ":web_components" ]
 }
 
-polymer_modulizer("progress_list_item") {
-  js_file = "progress_list_item.js"
-  html_file = "progress_list_item.html"
-  html_type = "dom-module"
-  auto_imports = oobe_auto_imports
-  namespace_rewrites = oobe_namespace_rewrites
-  migrated_imports = oobe_migrated_imports
+html_to_js("web_components") {
+  js_files = [ "progress_list_item.js" ]
 }
diff --git a/chrome/browser/resources/chromeos/login/components/progress_list_item/progress_list_item.html b/chrome/browser/resources/chromeos/login/components/progress_list_item/progress_list_item.html
index 164ef57a..3688310 100644
--- a/chrome/browser/resources/chromeos/login/components/progress_list_item/progress_list_item.html
+++ b/chrome/browser/resources/chromeos/login/components/progress_list_item/progress_list_item.html
@@ -3,94 +3,80 @@
 Use of this source code is governed by a BSD-style license that can be
 found in the LICENSE file.
 -->
-<link rel="import" href="chrome://resources/html/polymer.html">
-
-<link rel="import" href="chrome://resources/cr_elements/icons.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html">
-
-<link rel="import" href="../behaviors/oobe_i18n_behavior.html">
-<link rel="import" href="../common_styles/common_styles.html">
-
 <!--
-  Element for list of tasks with tri-state icon (pending, active, completed)
+Element for list of tasks with tri-state icon (pending, active, completed)
 
-  Example:
-    <progress-list-item text-key="thirdItemKey"
-        active="[[equal_(step, 3)]]"
-        completed="[[greater_(step, 3)]]">
-    </progress-list-item>
+Example:
+  <progress-list-item text-key="thirdItemKey"
+      active="[[equal_(step, 3)]]"
+      completed="[[greater_(step, 3)]]">
+  </progress-list-item>
 
-  Attributes and properties:
-    'textKey' - localization key for the item text
-    'activeKey' - if specified, overrides textKey for active state
-    'completedKey' - if specified, overrides textKey for completed state
-    'active' - if set, the item is considered to be in active state.
-    'completed' - if active is not set, and completed is set, the item is
-                  considered to be in completed state.
+Attributes and properties:
+  'textKey' - localization key for the item text
+  'activeKey' - if specified, overrides textKey for active state
+  'completedKey' - if specified, overrides textKey for completed state
+  'active' - if set, the item is considered to be in active state.
+  'completed' - if active is not set, and completed is set, the item is
+                considered to be in completed state.
 -->
-<dom-module id="progress-list-item">
-  <template>
-    <style include="oobe-common-styles">
-      #container {
-        height: 56px;
-      }
+<style include="oobe-common-styles">
+  #container {
+    height: 56px;
+  }
 
-      #icon {
-        min-width: 48px;
-      }
+  #icon {
+    min-width: 48px;
+  }
 
-      #icon-pending {
-        background-color: var(--cros-icon-color-disabled);
-        border-radius: 50%;
-        height: 8px;
-        margin-inline-start: 8px;
-        width: 8px;
-      }
+  #icon-pending {
+    background-color: var(--cros-icon-color-disabled);
+    border-radius: 50%;
+    height: 8px;
+    margin-inline-start: 8px;
+    width: 8px;
+  }
 
-      #icon-active {
-        height: 24px;
-        width: 24px;
-      }
+  #icon-active {
+    height: 24px;
+    width: 24px;
+  }
 
-      #icon-completed {
-        color: var(--cros-icon-color-blue);
-      }
+  #icon-completed {
+    color: var(--cros-icon-color-blue);
+  }
 
-      #text {
-        color: var(--oobe-text-color);
-        font-family: var(--oobe-default-font-family);
-        font-size: 15px;
-        line-height: 16px;
-      }
+  #text {
+    color: var(--oobe-text-color);
+    font-family: var(--oobe-default-font-family);
+    font-size: 15px;
+    line-height: 16px;
+  }
 
-      #text-active {
-        color: var(--cros-text-color-primary);
-      }
-    </style>
+  #text-active {
+    color: var(--cros-text-color-primary);
+  }
+</style>
 
-    <div class="flex layout horizontal center" id="container" role="listitem">
-      <div id="icon">
-        <div id="icon-pending" class="dot"
-            hidden="[[hidePending_(active, completed)]]"></div>
-        <paper-spinner-lite id="icon-active" hidden="[[!active]]" active>
-        </paper-spinner-lite>
-        <iron-icon id="icon-completed" icon="cr:check"
-              hidden="[[hideCompleted_(active, completed)]]"></iron-icon>
-      </div>
-      <div id="text" class="content">
-        <div id="text-pending" hidden="[[hidePending_(active, completed)]]">
-          [[i18nDynamic(locale, textKey)]]
-        </div>
-        <div id="text-active" hidden="[[!active]]">
-          [[fallbackText(locale, activeKey, textKey)]]
-        </div>
-        <div id="text-completed"
-              hidden="[[hideCompleted_(active, completed)]]">
-          [[fallbackText(locale, completedKey, textKey)]]
-        </div>
-      </div>
+<div class="flex layout horizontal center" id="container" role="listitem">
+  <div id="icon">
+    <div id="icon-pending" class="dot"
+        hidden="[[hidePending_(active, completed)]]"></div>
+    <paper-spinner-lite id="icon-active" hidden="[[!active]]" active>
+    </paper-spinner-lite>
+    <iron-icon id="icon-completed" icon="cr:check"
+          hidden="[[hideCompleted_(active, completed)]]"></iron-icon>
+  </div>
+  <div id="text" class="content">
+    <div id="text-pending" hidden="[[hidePending_(active, completed)]]">
+      [[i18nDynamic(locale, textKey)]]
     </div>
-  </template>
-  <script src="progress_list_item.js"></script>
-</dom-module>
+    <div id="text-active" hidden="[[!active]]">
+      [[fallbackText(locale, activeKey, textKey)]]
+    </div>
+    <div id="text-completed"
+          hidden="[[hideCompleted_(active, completed)]]">
+      [[fallbackText(locale, completedKey, textKey)]]
+    </div>
+  </div>
+</div>
diff --git a/chrome/browser/resources/chromeos/login/components/progress_list_item/progress_list_item.js b/chrome/browser/resources/chromeos/login/components/progress_list_item/progress_list_item.js
index afe2b6a..950afcab 100644
--- a/chrome/browser/resources/chromeos/login/components/progress_list_item/progress_list_item.js
+++ b/chrome/browser/resources/chromeos/login/components/progress_list_item/progress_list_item.js
@@ -2,15 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-/* #js_imports_placeholder */
+import '//resources/cr_elements/icons.html.js';
+import '//resources/polymer/v3_0/iron-icon/iron-icon.js';
+import '//resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js';
+import '../common_styles/common_styles.m.js';
+
+import {html, mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {OobeI18nBehavior, OobeI18nBehaviorInterface} from '../behaviors/oobe_i18n_behavior.m.js';
+
 
 /**
  * @constructor
  * @extends {PolymerElement}
  * @implements {OobeI18nBehaviorInterface}
  */
-const ProgressListItemBase =
-    Polymer.mixinBehaviors([OobeI18nBehavior], Polymer.Element);
+const ProgressListItemBase = mixinBehaviors([OobeI18nBehavior], PolymerElement);
 
 /**
  * @polymer
@@ -20,7 +27,9 @@
     return 'progress-list-item';
   }
 
-  /* #html_template_placeholder */
+  static get template() {
+    return html`{__html_template__}`;
+  }
 
   static get properties() {
     return {
diff --git a/chrome/browser/resources/chromeos/login/oobe_auto_imports.gni b/chrome/browser/resources/chromeos/login/oobe_auto_imports.gni
index 0ed2209f..e67ee8ff 100644
--- a/chrome/browser/resources/chromeos/login/oobe_auto_imports.gni
+++ b/chrome/browser/resources/chromeos/login/oobe_auto_imports.gni
@@ -114,6 +114,7 @@
   "ash/webui/common/resources/network/onc_mojo.html",
   "chrome/browser/resources/chromeos/login/components/gaia_button.html",
   "chrome/browser/resources/chromeos/login/components/notification_card.html",
+  "chrome/browser/resources/chromeos/login/components/progress_list_item/progress_list_item.html",
   "chrome/browser/resources/chromeos/login/components/security_token_pin.html",
   "chrome/browser/resources/chromeos/login/screens/common/offline_ad_login.html",
   "ash/webui/common/resources/quick_unlock/lock_screen_constants.html",
diff --git a/chrome/browser/resources/chromeos/login/screens/oobe/BUILD.gn b/chrome/browser/resources/chromeos/login/screens/oobe/BUILD.gn
index be7e199..bbd1407 100644
--- a/chrome/browser/resources/chromeos/login/screens/oobe/BUILD.gn
+++ b/chrome/browser/resources/chromeos/login/screens/oobe/BUILD.gn
@@ -79,7 +79,7 @@
     "../../components/buttons:oobe_back_button.m",
     "../../components/buttons:oobe_text_button.m",
     "../../components/dialogs:oobe_adaptive_dialog.m",
-    "../../components/progress_list_item:progress_list_item.m",
+    "../../components/progress_list_item:progress_list_item",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
   ]
   extra_deps = [ ":web_components" ]
diff --git a/chrome/browser/resources/chromeos/login/screens/oobe/demo_setup.js b/chrome/browser/resources/chromeos/login/screens/oobe/demo_setup.js
index 930457cf..e5ddda5 100644
--- a/chrome/browser/resources/chromeos/login/screens/oobe/demo_setup.js
+++ b/chrome/browser/resources/chromeos/login/screens/oobe/demo_setup.js
@@ -14,7 +14,7 @@
 import '../../components/common_styles/common_styles.m.js';
 import '../../components/common_styles/oobe_dialog_host_styles.m.js';
 import '../../components/dialogs/oobe_adaptive_dialog.m.js';
-import '../../components/progress_list_item/progress_list_item.m.js';
+import '../../components/progress_list_item/progress_list_item.js';
 
 import {loadTimeData} from '//resources/js/load_time_data.m.js';
 import {html, mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/chrome/browser/resources/new_tab_page/BUILD.gn b/chrome/browser/resources/new_tab_page/BUILD.gn
index e53133f..8b5c0712 100644
--- a/chrome/browser/resources/new_tab_page/BUILD.gn
+++ b/chrome/browser/resources/new_tab_page/BUILD.gn
@@ -67,6 +67,7 @@
     "//chrome/browser/new_tab_page/modules/recipes:mojo_bindings_js__generator",
     "//chrome/browser/ui/webui/new_tab_page:mojo_bindings_js__generator",
     "//chrome/browser/ui/webui/realbox:mojo_bindings_js__generator",
+    "//components/omnibox/browser:omnibox_js__generator",
   ]
   sources = [
     "$root_gen_dir/mojom-webui/chrome/browser/cart/chrome_cart.mojom-webui.js",
@@ -76,6 +77,7 @@
     "$root_gen_dir/mojom-webui/chrome/browser/new_tab_page/modules/recipes/recipes.mojom-webui.js",
     "$root_gen_dir/mojom-webui/chrome/browser/ui/webui/new_tab_page/new_tab_page.mojom-webui.js",
     "$root_gen_dir/mojom-webui/chrome/browser/ui/webui/realbox/realbox.mojom-webui.js",
+    "$root_gen_dir/mojom-webui/components/omnibox/browser/omnibox.mojom-webui.js",
   ]
 
   if (!is_official_build) {
@@ -116,6 +118,7 @@
     "//chrome/browser/ui/webui/new_tab_page:mojo_bindings_js",
     "//chrome/browser/ui/webui/realbox:mojo_bindings_js",
     "//chrome/common/search:mojo_bindings_js",
+    "//components/omnibox/browser:omnibox_js",
   ]
   if (!is_official_build) {
     deps += [ "//chrome/browser/ui/webui/new_tab_page/foo:mojo_bindings_js" ]
diff --git a/chrome/browser/resources/new_tab_page/new_tab_page.gni b/chrome/browser/resources/new_tab_page/new_tab_page.gni
index 3b989bb6..123aa97 100644
--- a/chrome/browser/resources/new_tab_page/new_tab_page.gni
+++ b/chrome/browser/resources/new_tab_page/new_tab_page.gni
@@ -67,6 +67,7 @@
   "photos.mojom-webui.js",
   "realbox.mojom-webui.js",
   "recipes.mojom-webui.js",
+  "omnibox.mojom-webui.js",
 ]
 
 if (!is_official_build) {
diff --git a/chrome/browser/resources/new_tab_page/realbox/realbox.ts b/chrome/browser/resources/new_tab_page/realbox/realbox.ts
index 70e3e80..4187d3f 100644
--- a/chrome/browser/resources/new_tab_page/realbox/realbox.ts
+++ b/chrome/browser/resources/new_tab_page/realbox/realbox.ts
@@ -11,6 +11,7 @@
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {loadTimeData} from '../i18n_setup.js';
+import {NavigationPredictor} from '../omnibox.mojom-webui.js';
 import {AutocompleteMatch, AutocompleteResult, PageCallbackRouter, PageHandlerInterface} from '../realbox.mojom-webui.js';
 import {decodeString16, mojoString16, mojoTimeDelta} from '../utils.js';
 
@@ -551,8 +552,12 @@
 
     if (e.key === 'ArrowDown') {
       this.$.matches.selectNext();
+      this.pageHandler_.onNavigationLikely(
+          this.selectedMatchIndex_, NavigationPredictor.kUpOrDownArrowButton);
     } else if (e.key === 'ArrowUp') {
       this.$.matches.selectPrevious();
+      this.pageHandler_.onNavigationLikely(
+          this.selectedMatchIndex_, NavigationPredictor.kUpOrDownArrowButton);
     } else if (e.key === 'Escape' || e.key === 'PageUp') {
       this.$.matches.selectFirst();
     } else if (e.key === 'PageDown') {
diff --git a/chrome/browser/resources/new_tab_page/realbox/realbox_match.ts b/chrome/browser/resources/new_tab_page/realbox/realbox_match.ts
index 99701c97..487214e3 100644
--- a/chrome/browser/resources/new_tab_page/realbox/realbox_match.ts
+++ b/chrome/browser/resources/new_tab_page/realbox/realbox_match.ts
@@ -12,6 +12,7 @@
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {loadTimeData} from '../i18n_setup.js';
+import {NavigationPredictor} from '../omnibox.mojom-webui.js';
 import {ACMatchClassification, AutocompleteMatch, PageHandlerInterface} from '../realbox.mojom-webui.js';
 import {decodeString16, mojoTimeTicks} from '../utils.js';
 
@@ -19,6 +20,7 @@
 import {RealboxIconElement} from './realbox_icon.js';
 import {getTemplate} from './realbox_match.html.js';
 
+
 // clang-format off
 /**
  * Bitmap used to decode the value of ACMatchClassification style
@@ -180,6 +182,7 @@
 
     this.addEventListener('click', (event) => this.onMatchClick_(event));
     this.addEventListener('focusin', () => this.onMatchFocusin_());
+    this.addEventListener('mousedown', () => this.onMatchMouseDown_());
   }
 
   //============================================================================
@@ -234,6 +237,11 @@
     }));
   }
 
+  private onMatchMouseDown_() {
+    this.pageHandler_.onNavigationLikely(
+        this.matchIndex, NavigationPredictor.kMouseDown);
+  }
+
   private onRemoveButtonClick_(e: MouseEvent) {
     if (e.button !== 0) {
       // Only handle main (generally left) button presses.
diff --git a/chrome/browser/resources/pdf/pdf_viewer.ts b/chrome/browser/resources/pdf/pdf_viewer.ts
index 12173c9..faa76a4 100644
--- a/chrome/browser/resources/pdf/pdf_viewer.ts
+++ b/chrome/browser/resources/pdf/pdf_viewer.ts
@@ -500,53 +500,39 @@
     this.currentController.setDisplayAnnotations(e.detail);
   }
 
-  private async enterPresentationMode_(): Promise<void> {
+  private onPresentClick_() {
     const scroller = this.$.scroller;
 
-    this.viewport.saveZoomState();
+    Promise
+        .all([
+          eventToPromise('fullscreenchange', scroller),
+          scroller.requestFullscreen(),
+        ])
+        .then(() => {
+          this.forceFit(FittingType.FIT_TO_HEIGHT);
 
-    await Promise.all([
-      eventToPromise('fullscreenchange', scroller),
-      scroller.requestFullscreen(),
-    ]);
+          // Switch viewport's wheel behavior.
+          this.viewport.setPresentationMode(true);
 
-    this.forceFit(FittingType.FIT_TO_HEIGHT);
+          // Set presentation mode, which restricts the content to read only
+          // (e.g. disable forms and links).
+          this.pluginController_!.setPresentationMode(true);
 
-    // Switch viewport's wheel behavior.
-    this.viewport.setPresentationMode(true);
+          // Revert back to the normal state when exiting Presentation mode.
+          eventToPromise('fullscreenchange', scroller).then(() => {
+            assert(document.fullscreenElement === null);
+            this.viewport.setPresentationMode(false);
+            this.pluginController_!.setPresentationMode(false);
 
-    // Set presentation mode, which restricts the content to read only
-    // (e.g. disable forms and links).
-    this.pluginController_!.setPresentationMode(true);
+            // Ensure that directional keys still work after exiting.
+            this.shadowRoot!.querySelector('embed')!.focus();
+          });
 
-    // Nothing else to do here. The viewport will be updated as a result
-    // of a 'resize' event callback.
+          // Nothing else to do here. The viewport will be updated as a result
+          // of a 'resize' event callback.
+        });
   }
 
-  private exitPresentationMode_(): void {
-    // Revert back to the normal state when exiting Presentation mode.
-    assert(document.fullscreenElement === null);
-    this.viewport.setPresentationMode(false);
-    this.pluginController_!.setPresentationMode(false);
-
-    // Ensure that directional keys still work after exiting.
-    this.shadowRoot!.querySelector('embed')!.focus();
-
-    // Set zoom back to original zoom before presentation mode.
-    this.viewport.restoreZoomState();
-  }
-
-  private async onPresentClick_() {
-    await this.enterPresentationMode_();
-
-    // When fullscreen changes, it means that the user exited Presentation
-    // mode.
-    await eventToPromise('fullscreenchange', this.$.scroller);
-
-    this.exitPresentationMode_();
-  }
-
-
   private onPropertiesClick_() {
     assert(!this.showPropertiesDialog_);
     this.showPropertiesDialog_ = true;
diff --git a/chrome/browser/resources/pdf/viewport.ts b/chrome/browser/resources/pdf/viewport.ts
index edbfc3e..f334ef2 100644
--- a/chrome/browser/resources/pdf/viewport.ts
+++ b/chrome/browser/resources/pdf/viewport.ts
@@ -77,13 +77,6 @@
   private internalZoom_: number = 1;
 
   /**
-   * Zoom state used to change zoom and fitting type to what it was
-   * originally when saved.
-   */
-  private savedZoom_: number|null = null;
-  private savedFittingType_: FittingType|null = null;
-
-  /**
    * Predefined zoom factors to be used when zooming in/out. These are in
    * ascending order.
    */
@@ -598,30 +591,6 @@
     });
   }
 
-  /**
-   * Save the current zoom and fitting type.
-   */
-  saveZoomState() {
-    this.savedZoom_ = this.internalZoom_;
-    this.savedFittingType_ = this.fittingType_;
-  }
-
-  /**
-   * Set zoom and fitting type to what it was when saved. See saveZoomState().
-   */
-  restoreZoomState() {
-    assert(
-        this.savedZoom_ !== null && this.savedFittingType_ !== null,
-        'No saved zoom state exists');
-    if (this.savedFittingType_ === FittingType.NONE) {
-      this.setZoom(this.savedZoom_);
-    } else {
-      this.setFittingType(this.savedFittingType_);
-    }
-    this.savedZoom_ = null;
-    this.savedFittingType_ = null;
-  }
-
   /** @param e Event containing the old browser zoom. */
   private updateZoomFromBrowserChange_(e: CustomEvent<number>) {
     const oldBrowserZoom = e.detail;
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/network_summary_item.html b/chrome/browser/resources/settings/chromeos/internet_page/network_summary_item.html
index 7ec5fe1..0bf0fb6 100644
--- a/chrome/browser/resources/settings/chromeos/internet_page/network_summary_item.html
+++ b/chrome/browser/resources/settings/chromeos/internet_page/network_summary_item.html
@@ -73,10 +73,12 @@
 
     <template is="dom-if" if="[[showArrowButton_(activeNetworkState,
                                   deviceState, networkStateList)]]">
-      <cr-icon-button class="subpage-arrow"
+      <cr-icon-button id="networkSummaryItemRowArrowIcon"
+          class="subpage-arrow"
           aria-labelledby="networkTitleText"
           aria-describedby="networkState networkIcon"
-          aria-roledescription="$i18n{subpageArrowRoleDescription}">
+          aria-roledescription="$i18n{subpageArrowRoleDescription}"
+          on-click="onShowDetailsArrowTap_">
       </cr-icon-button>
     </template>
   </div>
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/network_summary_item.js b/chrome/browser/resources/settings/chromeos/internet_page/network_summary_item.js
index aefb75b..0d5ced2 100644
--- a/chrome/browser/resources/settings/chromeos/internet_page/network_summary_item.js
+++ b/chrome/browser/resources/settings/chromeos/internet_page/network_summary_item.js
@@ -576,6 +576,45 @@
   }
 
   /**
+   * This handles clicking the subpage arrow. Clicking this icon can lead
+   * to showing the corresponding networks list or showing details about
+   * a network or doing nothing based on the device and networks states.
+   * TODO(b/253326370) Cleanup duplicate functionality between this
+   * function and `onShowDetailsTap_`.
+   * @param {!Event} event The enable button event.
+   * @private
+   */
+  onShowDetailsArrowTap_(event) {
+    if (this.shouldShowSubpage_(this.deviceState, this.networkStateList)) {
+      const showNetworksEvent = new CustomEvent('show-networks', {
+        bubbles: true,
+        composed: true,
+        detail: this.deviceState.type,
+      });
+      this.dispatchEvent(showNetworksEvent);
+    } else if (this.shouldShowDetails_(
+                   this.activeNetworkState, this.deviceState,
+                   this.networkStateList)) {
+      if (this.activeNetworkState.guid) {
+        const showDetailEvent = new CustomEvent('show-detail', {
+          bubbles: true,
+          composed: true,
+          detail: this.activeNetworkState,
+        });
+        this.dispatchEvent(showDetailEvent);
+      } else if (this.networkStateList.length > 0) {
+        const showDetailEvent = new CustomEvent('show-detail', {
+          bubbles: true,
+          composed: true,
+          detail: this.networkStateList[0],
+        });
+        this.dispatchEvent(showDetailEvent);
+      }
+    }
+    event.stopPropagation();
+  }
+
+  /**
    * @param {!OncMojo.NetworkStateProperties} activeNetworkState
    * @param {!OncMojo.DeviceStateProperties|undefined} deviceState
    * @param {!Array<!OncMojo.NetworkStateProperties>} networkStateList
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_util.js b/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_util.js
index 48d820a..5c9edbf 100644
--- a/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_util.js
+++ b/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_util.js
@@ -721,11 +721,11 @@
       return [
         {
           value: JAPANESE_INPUT_MODE.KANA,
-          name: 'inputMethodOptionsJapaneseInputModeRomaji',
+          name: 'inputMethodOptionsJapaneseInputModeKana',
         },
         {
           value: JAPANESE_INPUT_MODE.ROMAJI,
-          name: 'inputMethodOptionsJapaneseInputModeKana',
+          name: 'inputMethodOptionsJapaneseInputModeRomaji',
         },
       ];
     case OptionType.JAPANESE_PUNCTUATION_STYLE:
diff --git a/chrome/browser/resources/settings/chromeos/os_printing_page/cups_edit_printer_dialog.html b/chrome/browser/resources/settings/chromeos/os_printing_page/cups_edit_printer_dialog.html
index 7f67ebb..0a60ed7 100644
--- a/chrome/browser/resources/settings/chromeos/os_printing_page/cups_edit_printer_dialog.html
+++ b/chrome/browser/resources/settings/chromeos/os_printing_page/cups_edit_printer_dialog.html
@@ -127,13 +127,9 @@
       </div>
       <div id="ppdLabel" class="cr-form-field-label"
            hidden="[[pendingPrinter_.isManaged]]">
-        <div class="select-ppd-and-view">
-          <span>$i18n{selectDriverEditDialog}</span>
-          <cr-button class="ppd-button" on-click="onViewPpd_"
-                     disabled="[[printerInfoChanged_]]">
-            $i18n{cupsPrintersViewPpd}
-          </cr-button>
-        </div>
+        <localized-link localized-string="$i18n{selectDriver}"
+            link-url="$i18n{printingCUPSPrintPpdLearnMoreUrl}">
+        </localized-link>
       </div>
       <div class="settings-box two-line"
            hidden="[[pendingPrinter_.isManaged]]">
@@ -152,12 +148,6 @@
   </div>
   <div slot="dialog-buttons">
     <div>
-      <cr-button on-click="onLearnMoreTap_"
-                 hidden="[[pendingPrinter_.isManaged]]">
-        $i18n{cupsPrintersLearnMoreButtonTitle}
-      </cr-button>
-    </div>
-    <div>
       <div class="eula" id="eulaUrl" hidden="[[!eulaUrl_]]">
         <a href="[[eulaUrl_]]" target="_blank">$i18n{printerEulaNotice}</a>
       </div>
diff --git a/chrome/browser/resources/settings/chromeos/os_printing_page/cups_edit_printer_dialog.js b/chrome/browser/resources/settings/chromeos/os_printing_page/cups_edit_printer_dialog.js
index 86541b4..d97cea77 100644
--- a/chrome/browser/resources/settings/chromeos/os_printing_page/cups_edit_printer_dialog.js
+++ b/chrome/browser/resources/settings/chromeos/os_printing_page/cups_edit_printer_dialog.js
@@ -17,11 +17,10 @@
 import './cups_printer_dialog_error.js';
 import './cups_printer_shared_css.js';
 
+import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/ash/common/i18n_behavior.js';
 import {MojoInterfaceProvider, MojoInterfaceProviderImpl} from 'chrome://resources/ash/common/network/mojo_interface_provider.js';
 import {NetworkListenerBehavior, NetworkListenerBehaviorInterface} from 'chrome://resources/ash/common/network/network_listener_behavior.js';
 import {OncMojo} from 'chrome://resources/ash/common/network/onc_mojo.js';
-import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/ash/common/i18n_behavior.js';
-import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {CrosNetworkConfigRemote, FilterType, NetworkStateProperties, NO_LIMIT} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js';
 import {NetworkType} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js';
 import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
@@ -29,23 +28,8 @@
 import {recordSettingChange} from '../metrics_recorder.js';
 
 import {getBaseName, getErrorText, isNameAndAddressValid, isNetworkProtocol, isPPDInfoValid} from './cups_printer_dialog_util.js';
-import {CupsPrinterInfo, CupsPrinterPpdInfo, CupsPrintersBrowserProxy, CupsPrintersBrowserProxyImpl, ManufacturersInfo, ModelsInfo, PrinterPpdMakeModel, PrinterSetupResult} from './cups_printers_browser_proxy.js';
+import {CupsPrinterInfo, CupsPrintersBrowserProxy, CupsPrintersBrowserProxyImpl, ManufacturersInfo, ModelsInfo, PrinterPpdMakeModel, PrinterSetupResult} from './cups_printers_browser_proxy.js';
 
-/**
- * The types of actions that can be performed with the edit dialog.  These
- * values are written to logs and used as metrics.  New enum values can be
- * added, but existing values must never be renumbered or deleted and reused.
- * See PrinterEditDialogActions enum in tools/metrics/hisograms/enums.xml.
- * @enum {number}
- * @const
- */
-const DIALOG_ACTIONS = {
-  DIALOG_OPENED: 0,
-  VIEW_PPD_CLICKED: 1,
-};
-
-/** Keyword used for recording metrics */
-const METRICS_KEYWORD = 'Printing.CUPS.EditDialog';
 
 /**
  * @constructor
@@ -216,10 +200,6 @@
   connectedCallback() {
     super.connectedCallback();
 
-    chrome.metricsPrivate.recordEnumerationValue(
-        METRICS_KEYWORD, DIALOG_ACTIONS.DIALOG_OPENED,
-        Object.keys(DIALOG_ACTIONS).length);
-
     // Create a copy of activePrinter so that we can modify its fields.
     this.pendingPrinter_ = /** @type{CupsPrinterInfo} */
         (Object.assign({}, this.activePrinter));
@@ -449,66 +429,6 @@
     this.eulaUrl_ = eulaUrl;
   }
 
-  /**
-   * Handler for retrieveCupsPrinterPpd success.
-   * @param {!CupsPrinterPpdInfo} ppdInfo
-   * @private
-   */
-  onRetrieveCupsPrinterPpdSucceeded_(ppdInfo) {
-    let eulaHtml = '';
-    if (this.eulaUrl_) {
-      const linkText = this.i18n('printerEulaNotice');
-      eulaHtml = `<a href=${this.eulaUrl_} target="_blank">
-           ${linkText}</a>
-           <p>============================================================</p>`;
-    }
-
-    const htmlText = '<!DOCTYPE html><html><body><h1>' +
-        loadTimeData.getStringF('cupsPrintersPpdFor', ppdInfo.printerName) +
-        '</h1>' + eulaHtml + '<p><pre>' + ppdInfo.ppd + '</pre></p>';
-
-    const win = window.open('');
-    win.document.title = ppdInfo.printerName;
-    win.document.body.innerHTML = htmlText;
-  }
-
-  /**
-   * Handler for retrieveCupsPrinterPpd failure.
-   * @param {*} ppdInfo
-   * @private
-   */
-  onRetrieveCupsPrinterPpdFailed_(ppdInfo) {
-    const htmlText = '<!DOCTYPE html><html><body><h1>' +
-        loadTimeData.getStringF('cupsPrintersPpdFor', ppdInfo.printerName) +
-        '</h1><p>' + this.i18n('cupsPrintersViewPpdErrorMessage') + '</p>';
-
-    const win = window.open('');
-    win.document.title = ppdInfo.printerName;
-    win.document.body.innerHTML = htmlText;
-  }
-
-  /** @private */
-  onViewPpd_() {
-    chrome.metricsPrivate.recordEnumerationValue(
-        METRICS_KEYWORD, DIALOG_ACTIONS.VIEW_PPD_CLICKED,
-        Object.keys(DIALOG_ACTIONS).length);
-
-    // We always use the activePrinter (the printer when the dialog was first
-    // displayed) when viewing the PPD.  Once the user has modified the dialog,
-    // the view PPD button is no longer active.
-    this.browserProxy_
-        .retrieveCupsPrinterPpd(
-            this.activePrinter.printerId, this.activePrinter.printerName)
-        .then(
-            this.onRetrieveCupsPrinterPpdSucceeded_.bind(this),
-            this.onRetrieveCupsPrinterPpdFailed_.bind(this));
-  }
-
-  /** @private */
-  onLearnMoreTap_() {
-    window.open(this.i18n('printingCUPSPrintPpdLearnMoreUrl'));
-  }
-
   /** @private */
   onBrowseFile_() {
     this.browserProxy_.getCupsPrinterPPDPath().then(
diff --git a/chrome/browser/resources/settings/chromeos/os_printing_page/cups_printer_shared_css.html b/chrome/browser/resources/settings/chromeos/os_printing_page/cups_printer_shared_css.html
index 9d3e8279..27b4c8a 100644
--- a/chrome/browser/resources/settings/chromeos/os_printing_page/cups_printer_shared_css.html
+++ b/chrome/browser/resources/settings/chromeos/os_printing_page/cups_printer_shared_css.html
@@ -38,19 +38,6 @@
       margin-inline-start: 12px;
     }
 
-    [slot='dialog-body'] .cr-form-field-label .select-ppd-and-view {
-      align-items: center;
-      display: flex;
-    }
-
-    [slot='dialog-body'] .cr-form-field-label .select-ppd-and-view .ppd-button {
-      background: none;
-      border: none;
-      cursor: pointer;
-      margin-inline-start: 12px;
-      padding: 0;
-    }
-
     [slot='dialog-body'] .last {
       margin-top: 20px;
     }
diff --git a/chrome/browser/resources/settings/chromeos/os_printing_page/cups_printers_browser_proxy.js b/chrome/browser/resources/settings/chromeos/os_printing_page/cups_printers_browser_proxy.js
index db436e7e..e59830a 100644
--- a/chrome/browser/resources/settings/chromeos/os_printing_page/cups_printers_browser_proxy.js
+++ b/chrome/browser/resources/settings/chromeos/os_printing_page/cups_printers_browser_proxy.js
@@ -46,16 +46,6 @@
 
 /**
  * @typedef {{
- *   printerName: string,
- *   ppd: string,
- * }}
- *
- * Note: |ppd| is undefined in the case of a failed response.
- */
-export let CupsPrinterPpdInfo;
-
-/**
- * @typedef {{
  *   success: boolean,
  *   manufacturers: Array<string>
  * }}
@@ -157,14 +147,6 @@
   removeCupsPrinter(printerId, printerName) {}
 
   /**
-   * @param {string} printerId
-   * @param {string} printerName
-   * @return {!Promise<!CupsPrinterPpdInfo>} The contents of the PPD for
-   *     printerId.
-   */
-  retrieveCupsPrinterPpd(printerId, printerName) {}
-
-  /**
    * @return {!Promise<string>} The full path of the printer PPD file.
    */
   getCupsPrinterPPDPath() {}
@@ -283,11 +265,6 @@
   }
 
   /** @override */
-  retrieveCupsPrinterPpd(printerId, printerName) {
-    return sendWithPromise('retrieveCupsPrinterPpd', printerId, printerName);
-  }
-
-  /** @override */
   addCupsPrinter(newPrinter) {
     return sendWithPromise('addCupsPrinter', newPrinter);
   }
diff --git a/chrome/browser/resources/webui_gallery/BUILD.gn b/chrome/browser/resources/webui_gallery/BUILD.gn
index 259e6a64..dcaad0f5 100644
--- a/chrome/browser/resources/webui_gallery/BUILD.gn
+++ b/chrome/browser/resources/webui_gallery/BUILD.gn
@@ -61,27 +61,27 @@
 
   input_files = [
     "demos/buttons_demo.html",
-    "demos/demo.css",
-    "demos/card/card_demo.html",
-    "demos/cr_a11y_announcer_demo.html",
-    "demos/cr_action_menu_demo.html",
+    "demos/card/index.html",
+    "demos/cr_a11y_announcer/index.html",
+    "demos/cr_action_menu/index.html",
     "demos/cr_checkbox_demo.html",
-    "demos/cr_dialog_demo.html",
-    "demos/cr_icons/cr_icons_demo.html",
-    "demos/cr_input/cr_input_demo.html",
+    "demos/cr_dialog/index.html",
+    "demos/cr_icons/index.html",
+    "demos/cr_input/index.html",
     "demos/cr_radio_demo.html",
-    "demos/cr_slider/cr_slider_demo.html",
-    "demos/cr_tab_box/cr_tab_box_demo.html",
-    "demos/cr_tabs/cr_tabs_demo.html",
-    "demos/cr_toast/cr_toast_demo.html",
-    "demos/cr_toolbar/cr_toolbar_demo.html",
-    "demos/cr_tree/cr_tree_demo.html",
+    "demos/cr_slider/index.html",
+    "demos/cr_tab_box/index.html",
+    "demos/cr_tabs/index.html",
+    "demos/cr_toast/index.html",
     "demos/cr_toggle_demo.html",
-    "demos/md_select/md_select_demo.html",
+    "demos/cr_toolbar/index.html",
+    "demos/cr_tree/index.html",
+    "demos/demo.css",
+    "demos/md_select/index.html",
     "demos/nav_menu/index.html",
     "demos/progress_indicator_nonpolymer_demo.html",
     "demos/progress_indicator_polymer_demo.html",
-    "demos/scroll_view/scroll_view_demo.html",
+    "demos/scroll_view/index.html",
     "webui_gallery.html",
   ]
 
diff --git a/chrome/browser/resources/webui_gallery/app.ts b/chrome/browser/resources/webui_gallery/app.ts
index 52e426a..5d4b980 100644
--- a/chrome/browser/resources/webui_gallery/app.ts
+++ b/chrome/browser/resources/webui_gallery/app.ts
@@ -37,12 +37,12 @@
             {
               name: 'Accessibility Live Regions',
               path: 'a11y',
-              src: 'cr_a11y_announcer_demo.html',
+              src: 'cr_a11y_announcer/index.html',
             },
             {
               name: 'Action Menus',
               path: 'action-menus',
-              src: 'cr_action_menu_demo.html',
+              src: 'cr_action_menu/index.html',
             },
             {
               name: 'Buttons',
@@ -52,7 +52,7 @@
             {
               name: 'Cards and rows',
               path: 'cards',
-              src: 'card/card_demo.html',
+              src: 'card/index.html',
             },
             {
               name: 'Checkboxes',
@@ -62,17 +62,17 @@
             {
               name: 'Dialogs',
               path: 'dialogs',
-              src: 'cr_dialog_demo.html',
+              src: 'cr_dialog/index.html',
             },
             {
               name: 'Icons',
               path: 'icons',
-              src: 'cr_icons/cr_icons_demo.html',
+              src: 'cr_icons/index.html',
             },
             {
               name: 'Inputs',
               path: 'inputs',
-              src: 'cr_input/cr_input_demo.html',
+              src: 'cr_input/index.html',
             },
             {
               name: 'Navigation menus',
@@ -97,32 +97,32 @@
             {
               name: 'Scroll view',
               path: 'scroll-view',
-              src: 'scroll_view/scroll_view_demo.html',
+              src: 'scroll_view/index.html',
             },
             {
               name: 'Select menu',
               path: 'select-menu',
-              src: 'md_select/md_select_demo.html',
+              src: 'md_select/index.html',
             },
             {
               name: 'Sliders',
               path: 'sliders',
-              src: 'cr_slider/cr_slider_demo.html',
+              src: 'cr_slider/index.html',
             },
             {
               name: 'Tabs, non-Polymer',
               path: 'tabs1',
-              src: 'cr_tab_box/cr_tab_box_demo.html',
+              src: 'cr_tab_box/index.html',
             },
             {
               name: 'Tabs, Polymer',
               path: 'tabs2',
-              src: 'cr_tabs/cr_tabs_demo.html',
+              src: 'cr_tabs/index.html',
             },
             {
               name: 'Toast',
               path: 'toast',
-              src: 'cr_toast/cr_toast_demo.html',
+              src: 'cr_toast/index.html',
             },
             {
               name: 'Toggles',
@@ -132,12 +132,12 @@
             {
               name: 'Toolbar',
               path: 'toolbar',
-              src: 'cr_toolbar/cr_toolbar_demo.html',
+              src: 'cr_toolbar/index.html',
             },
             {
               name: 'Tree, non-Polymer',
               path: 'tree',
-              src: 'cr_tree/cr_tree_demo.html',
+              src: 'cr_tree/index.html',
             },
           ];
         },
diff --git a/chrome/browser/resources/webui_gallery/demos/buttons_demo.html b/chrome/browser/resources/webui_gallery/demos/buttons_demo.html
index 9a0f4145..5ea03ae 100644
--- a/chrome/browser/resources/webui_gallery/demos/buttons_demo.html
+++ b/chrome/browser/resources/webui_gallery/demos/buttons_demo.html
@@ -67,16 +67,16 @@
       </template>
     </dom-bind>
 
-    <script src="chrome://resources/polymer/v3_0/iron-collapse/iron-collapse.js"
+    <script src="//resources/polymer/v3_0/iron-collapse/iron-collapse.js"
         type="module"></script>
-    <script src="chrome://resources/cr_elements/icons.html.js" type="module">
+    <script src="//resources/cr_elements/icons.html.js" type="module">
     </script>
     <script
-        src="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.js"
+        src="//resources/cr_elements/cr_expand_button/cr_expand_button.js"
         type="module"></script>
-    <script src="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js"
+    <script src="//resources/cr_elements/cr_icon_button/cr_icon_button.js"
         type="module"></script>
-    <script src="chrome://resources/cr_elements/cr_button/cr_button.js"
+    <script src="//resources/cr_elements/cr_button/cr_button.js"
         type="module"></script>
   </body>
 </html>
diff --git a/chrome/browser/resources/webui_gallery/demos/card/card_demo.html b/chrome/browser/resources/webui_gallery/demos/card/card_demo.html
index 730d51d..3a2ce1a 100644
--- a/chrome/browser/resources/webui_gallery/demos/card/card_demo.html
+++ b/chrome/browser/resources/webui_gallery/demos/card/card_demo.html
@@ -1,12 +1,80 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Cards demo</title>
-    <link rel="stylesheet" href="../demo.css">
-  </head>
-  <body>
-    <card-demo></card-demo>
-    <script src="card_demo_component.js" type="module"></script>
-  </body>
-</html>
+<style include="cr-page-host-style cr-shared-style">
+  .card {
+    background-color: var(--cr-card-background-color);
+    border-radius: var(--cr-card-border-radius);
+    box-shadow: var(--cr-card-shadow);
+    margin: 0 auto;
+    margin-block-end: 36px;
+    max-width: var(--card-max-width);
+  }
+
+  .flex {
+    flex: 1;
+  }
+
+  #expandedContent {
+    padding-inline-end: var(--cr-section-padding);
+    padding-inline-start: var(--cr-section-indent-padding);
+  }
+</style>
+<div class="cr-centered-card-container">
+  <h2>Cards and rows with content</h2>
+  <div class="card">
+    <div class="cr-row first">
+      <div class="cr-padded-text">This is an example of a row.</div>
+    </div>
+
+    <div class="cr-row">
+      <div class="cr-padded-text">
+        <div>Some title text</div>
+        <div class="cr-secondary-text">Some secondary text</div>
+      </div>
+    </div>
+
+    <div class="cr-row">
+      <div class="cr-padded-text flex">
+        Some text that takes up most of the row's space
+      </div>
+      <cr-button class="action-button">Button 1</cr-button>
+      <cr-button class="cr-button-gap">Button 2</cr-button>
+    </div>
+
+    <div class="cr-row">
+      A row...
+    </div>
+    <div id="continuationRow" class="cr-row continuation">
+      ...that continues into another row.
+    </div>
+  </div>
+
+  <h2>Cards with &lt;cr-link-row&gt; instances</h2>
+  <div class="card">
+    <cr-link-row label="A full length link row"></cr-link-row>
+    <cr-link-row class="hr" label="A full length link row"
+        sub-label="With some secondary text">
+    </cr-link-row>
+    <cr-link-row class="hr" external
+        label="A row that links to an external website"
+        on-click="onExternalLinkClick_"></cr-link-row>
+    <cr-link-row no-hover class="hr" label="Link row with no hover effect">
+    </cr-link-row>
+    <cr-link-row start-icon="cr:check" label="Row with an icon"></cr-link-row>
+    <cr-link-row class="hr" using-slotted-label>
+      <div slot="label">A link row that uses slotted content</div>
+      <div slot="sub-label">And slotted sublabel</div>
+      <iron-icon icon="cr:check"></iron-icon>
+    </cr-link-row>
+  </div>
+
+  <h2>Other examples</h2>
+  <div class="card">
+    <cr-expand-button class="cr-row first" expanded="{{expanded_}}">
+      A row that expands...
+    </cr-expand-button>
+    <iron-collapse id="expandedContent" opened="[[expanded_]]">
+      <div class="cr-padded-text">...into more rows!</div>
+      <div class="cr-padded-text hr">...into more rows!</div>
+      <div class="cr-padded-text hr">...into more rows!</div>
+    </iron-collapse>
+  </div>
+</div>
diff --git a/chrome/browser/resources/webui_gallery/demos/card/card_demo.ts b/chrome/browser/resources/webui_gallery/demos/card/card_demo.ts
new file mode 100644
index 0000000..f432d46
--- /dev/null
+++ b/chrome/browser/resources/webui_gallery/demos/card/card_demo.ts
@@ -0,0 +1,41 @@
+// 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 '//resources/cr_elements/cr_button/cr_button.js';
+import '//resources/cr_elements/cr_expand_button/cr_expand_button.js';
+import '//resources/cr_elements/cr_link_row/cr_link_row.js';
+import '//resources/cr_elements/cr_page_host_style.css.js';
+import '//resources/cr_elements/cr_shared_style.css.js';
+import '//resources/cr_elements/cr_shared_vars.css.js';
+import '//resources/cr_elements/icons.html.js';
+import '//resources/polymer/v3_0/iron-collapse/iron-collapse.js';
+import '//resources/polymer/v3_0/iron-icon/iron-icon.js';
+
+import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {getTemplate} from './card_demo.html.js';
+
+class CardDemoElement extends PolymerElement {
+  static get is() {
+    return 'card-demo';
+  }
+
+  static get template() {
+    return getTemplate();
+  }
+
+  static get properties() {
+    return {
+      expanded_: Boolean,
+    };
+  }
+
+  private expanded_: boolean = false;
+
+  private onExternalLinkClick_() {
+    window.open('https://chromium.org');
+  }
+}
+
+customElements.define(CardDemoElement.is, CardDemoElement);
diff --git a/chrome/browser/resources/webui_gallery/demos/card/card_demo_component.html b/chrome/browser/resources/webui_gallery/demos/card/card_demo_component.html
deleted file mode 100644
index 3a2ce1a..0000000
--- a/chrome/browser/resources/webui_gallery/demos/card/card_demo_component.html
+++ /dev/null
@@ -1,80 +0,0 @@
-<style include="cr-page-host-style cr-shared-style">
-  .card {
-    background-color: var(--cr-card-background-color);
-    border-radius: var(--cr-card-border-radius);
-    box-shadow: var(--cr-card-shadow);
-    margin: 0 auto;
-    margin-block-end: 36px;
-    max-width: var(--card-max-width);
-  }
-
-  .flex {
-    flex: 1;
-  }
-
-  #expandedContent {
-    padding-inline-end: var(--cr-section-padding);
-    padding-inline-start: var(--cr-section-indent-padding);
-  }
-</style>
-<div class="cr-centered-card-container">
-  <h2>Cards and rows with content</h2>
-  <div class="card">
-    <div class="cr-row first">
-      <div class="cr-padded-text">This is an example of a row.</div>
-    </div>
-
-    <div class="cr-row">
-      <div class="cr-padded-text">
-        <div>Some title text</div>
-        <div class="cr-secondary-text">Some secondary text</div>
-      </div>
-    </div>
-
-    <div class="cr-row">
-      <div class="cr-padded-text flex">
-        Some text that takes up most of the row's space
-      </div>
-      <cr-button class="action-button">Button 1</cr-button>
-      <cr-button class="cr-button-gap">Button 2</cr-button>
-    </div>
-
-    <div class="cr-row">
-      A row...
-    </div>
-    <div id="continuationRow" class="cr-row continuation">
-      ...that continues into another row.
-    </div>
-  </div>
-
-  <h2>Cards with &lt;cr-link-row&gt; instances</h2>
-  <div class="card">
-    <cr-link-row label="A full length link row"></cr-link-row>
-    <cr-link-row class="hr" label="A full length link row"
-        sub-label="With some secondary text">
-    </cr-link-row>
-    <cr-link-row class="hr" external
-        label="A row that links to an external website"
-        on-click="onExternalLinkClick_"></cr-link-row>
-    <cr-link-row no-hover class="hr" label="Link row with no hover effect">
-    </cr-link-row>
-    <cr-link-row start-icon="cr:check" label="Row with an icon"></cr-link-row>
-    <cr-link-row class="hr" using-slotted-label>
-      <div slot="label">A link row that uses slotted content</div>
-      <div slot="sub-label">And slotted sublabel</div>
-      <iron-icon icon="cr:check"></iron-icon>
-    </cr-link-row>
-  </div>
-
-  <h2>Other examples</h2>
-  <div class="card">
-    <cr-expand-button class="cr-row first" expanded="{{expanded_}}">
-      A row that expands...
-    </cr-expand-button>
-    <iron-collapse id="expandedContent" opened="[[expanded_]]">
-      <div class="cr-padded-text">...into more rows!</div>
-      <div class="cr-padded-text hr">...into more rows!</div>
-      <div class="cr-padded-text hr">...into more rows!</div>
-    </iron-collapse>
-  </div>
-</div>
diff --git a/chrome/browser/resources/webui_gallery/demos/card/card_demo_component.ts b/chrome/browser/resources/webui_gallery/demos/card/card_demo_component.ts
deleted file mode 100644
index 1d55ea3..0000000
--- a/chrome/browser/resources/webui_gallery/demos/card/card_demo_component.ts
+++ /dev/null
@@ -1,41 +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 'chrome://resources/cr_elements/cr_button/cr_button.js';
-import 'chrome://resources/cr_elements/cr_expand_button/cr_expand_button.js';
-import 'chrome://resources/cr_elements/cr_link_row/cr_link_row.js';
-import 'chrome://resources/cr_elements/cr_page_host_style.css.js';
-import 'chrome://resources/cr_elements/cr_shared_style.css.js';
-import 'chrome://resources/cr_elements/cr_shared_vars.css.js';
-import 'chrome://resources/cr_elements/icons.html.js';
-import 'chrome://resources/polymer/v3_0/iron-collapse/iron-collapse.js';
-import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
-
-import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {getTemplate} from './card_demo_component.html.js';
-
-class CardDemoComponent extends PolymerElement {
-  static get is() {
-    return 'card-demo';
-  }
-
-  static get template() {
-    return getTemplate();
-  }
-
-  static get properties() {
-    return {
-      expanded_: Boolean,
-    };
-  }
-
-  private expanded_: boolean = false;
-
-  private onExternalLinkClick_() {
-    window.open('https://chromium.org');
-  }
-}
-
-customElements.define(CardDemoComponent.is, CardDemoComponent);
diff --git a/chrome/browser/resources/webui_gallery/demos/card/index.html b/chrome/browser/resources/webui_gallery/demos/card/index.html
new file mode 100644
index 0000000..5440a90
--- /dev/null
+++ b/chrome/browser/resources/webui_gallery/demos/card/index.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>Cards demo</title>
+    <link rel="stylesheet" href="../demo.css">
+  </head>
+  <body>
+    <card-demo></card-demo>
+    <script src="card_demo.js" type="module"></script>
+  </body>
+</html>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_a11y_announcer_demo_component.html b/chrome/browser/resources/webui_gallery/demos/cr_a11y_announcer/cr_a11y_announcer_demo.html
similarity index 91%
rename from chrome/browser/resources/webui_gallery/demos/cr_a11y_announcer_demo_component.html
rename to chrome/browser/resources/webui_gallery/demos/cr_a11y_announcer/cr_a11y_announcer_demo.html
index 1a642725..1fd995f 100644
--- a/chrome/browser/resources/webui_gallery/demos/cr_a11y_announcer_demo_component.html
+++ b/chrome/browser/resources/webui_gallery/demos/cr_a11y_announcer/cr_a11y_announcer_demo.html
@@ -1,4 +1,4 @@
-<link rel="stylesheet" href="demo.css">
+<link rel="stylesheet" href="../demo.css">
 <style>
   :host([force-show-announcer_]) cr-a11y-announcer {
     overflow: visible;
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_a11y_announcer_demo_component.ts b/chrome/browser/resources/webui_gallery/demos/cr_a11y_announcer/cr_a11y_announcer_demo.ts
similarity index 70%
rename from chrome/browser/resources/webui_gallery/demos/cr_a11y_announcer_demo_component.ts
rename to chrome/browser/resources/webui_gallery/demos/cr_a11y_announcer/cr_a11y_announcer_demo.ts
index 555d6bef..67b083ed 100644
--- a/chrome/browser/resources/webui_gallery/demos/cr_a11y_announcer_demo_component.ts
+++ b/chrome/browser/resources/webui_gallery/demos/cr_a11y_announcer/cr_a11y_announcer_demo.ts
@@ -2,21 +2,21 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'chrome://resources/cr_elements/cr_button/cr_button.js';
-import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js';
+import '//resources/cr_elements/cr_button/cr_button.js';
+import '//resources/cr_elements/cr_checkbox/cr_checkbox.js';
 
+import {getInstance as getAnnouncerInstance} from '//resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.js';
 import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {getInstance as getAnnouncerInstance} from 'chrome://resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.js';
 
-import {getTemplate} from './cr_a11y_announcer_demo_component.html.js';
+import {getTemplate} from './cr_a11y_announcer_demo.html.js';
 
-interface CrA11yAnnouncerDemoComponent {
+interface CrA11yAnnouncerDemoElement {
   $: {
     announcerContainer: HTMLElement,
   };
 }
 
-class CrA11yAnnouncerDemoComponent extends PolymerElement {
+class CrA11yAnnouncerDemoElement extends PolymerElement {
   static get is() {
     return 'cr-a11y-announcer-demo';
   }
@@ -55,4 +55,4 @@
 }
 
 customElements.define(
-    CrA11yAnnouncerDemoComponent.is, CrA11yAnnouncerDemoComponent);
+    CrA11yAnnouncerDemoElement.is, CrA11yAnnouncerDemoElement);
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_a11y_announcer_demo.html b/chrome/browser/resources/webui_gallery/demos/cr_a11y_announcer/index.html
similarity index 60%
rename from chrome/browser/resources/webui_gallery/demos/cr_a11y_announcer_demo.html
rename to chrome/browser/resources/webui_gallery/demos/cr_a11y_announcer/index.html
index 8850a885..97242895 100644
--- a/chrome/browser/resources/webui_gallery/demos/cr_a11y_announcer_demo.html
+++ b/chrome/browser/resources/webui_gallery/demos/cr_a11y_announcer/index.html
@@ -3,10 +3,10 @@
   <head>
     <meta charset="utf-8">
     <title>cr-a11y-announcer demo</title>
-    <link rel="stylesheet" href="demo.css">
+    <link rel="stylesheet" href="../demo.css">
   </head>
   <body>
     <cr-a11y-announcer-demo></cr-a11y-announcer-demo>
-    <script src="cr_a11y_announcer_demo_component.js" type="module"></script>
+    <script src="cr_a11y_announcer_demo.js" type="module"></script>
   </body>
 </html>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_action_menu_demo_component.html b/chrome/browser/resources/webui_gallery/demos/cr_action_menu/cr_action_menu_demo.html
similarity index 97%
rename from chrome/browser/resources/webui_gallery/demos/cr_action_menu_demo_component.html
rename to chrome/browser/resources/webui_gallery/demos/cr_action_menu/cr_action_menu_demo.html
index b1018628..e8823748 100644
--- a/chrome/browser/resources/webui_gallery/demos/cr_action_menu_demo_component.html
+++ b/chrome/browser/resources/webui_gallery/demos/cr_action_menu/cr_action_menu_demo.html
@@ -1,4 +1,4 @@
-<link rel="stylesheet" href="demo.css">
+<link rel="stylesheet" href="../demo.css">
 
 <style include="cr-icons">
   cr-input {
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_action_menu_demo_component.ts b/chrome/browser/resources/webui_gallery/demos/cr_action_menu/cr_action_menu_demo.ts
similarity index 76%
rename from chrome/browser/resources/webui_gallery/demos/cr_action_menu_demo_component.ts
rename to chrome/browser/resources/webui_gallery/demos/cr_action_menu/cr_action_menu_demo.ts
index f021171..0e5e52b 100644
--- a/chrome/browser/resources/webui_gallery/demos/cr_action_menu_demo_component.ts
+++ b/chrome/browser/resources/webui_gallery/demos/cr_action_menu/cr_action_menu_demo.ts
@@ -2,28 +2,28 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'chrome://resources/cr_elements/cr_icons.css.js';
-import 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js';
-import 'chrome://resources/cr_elements/cr_button/cr_button.js';
-import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js';
-import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js';
-import 'chrome://resources/cr_elements/cr_input/cr_input.js';
-import 'chrome://resources/cr_elements/icons.html.js';
-import 'chrome://resources/cr_elements/cr_shared_vars.css.js';
+import '//resources/cr_elements/cr_icons.css.js';
+import '//resources/cr_elements/cr_action_menu/cr_action_menu.js';
+import '//resources/cr_elements/cr_button/cr_button.js';
+import '//resources/cr_elements/cr_checkbox/cr_checkbox.js';
+import '//resources/cr_elements/cr_icon_button/cr_icon_button.js';
+import '//resources/cr_elements/cr_input/cr_input.js';
+import '//resources/cr_elements/icons.html.js';
+import '//resources/cr_elements/cr_shared_vars.css.js';
 
+import {AnchorAlignment, CrActionMenuElement, ShowAtPositionConfig} from '//resources/cr_elements/cr_action_menu/cr_action_menu.js';
+import {CrInputElement} from '//resources/cr_elements/cr_input/cr_input.js';
 import {DomRepeatEvent, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {AnchorAlignment, CrActionMenuElement, ShowAtPositionConfig} from 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js';
-import {CrInputElement} from 'chrome://resources/cr_elements/cr_input/cr_input.js';
 
-import {getTemplate} from './cr_action_menu_demo_component.html.js';
+import {getTemplate} from './cr_action_menu_demo.html.js';
 
-interface CrActionMenuDemoComponent {
+interface CrActionMenuDemoElement {
   $: {
     menu: CrActionMenuElement,
   };
 }
 
-class CrActionMenuDemoComponent extends PolymerElement {
+class CrActionMenuDemoElement extends PolymerElement {
   static get is() {
     return 'cr-action-menu-demo';
   }
@@ -130,4 +130,4 @@
   }
 }
 
-customElements.define(CrActionMenuDemoComponent.is, CrActionMenuDemoComponent);
+customElements.define(CrActionMenuDemoElement.is, CrActionMenuDemoElement);
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_action_menu_demo.html b/chrome/browser/resources/webui_gallery/demos/cr_action_menu/index.html
similarity index 60%
rename from chrome/browser/resources/webui_gallery/demos/cr_action_menu_demo.html
rename to chrome/browser/resources/webui_gallery/demos/cr_action_menu/index.html
index 66afca71..57b6aef 100644
--- a/chrome/browser/resources/webui_gallery/demos/cr_action_menu_demo.html
+++ b/chrome/browser/resources/webui_gallery/demos/cr_action_menu/index.html
@@ -3,10 +3,10 @@
   <head>
     <meta charset="utf-8">
     <title>cr-action-menu demo</title>
-    <link rel="stylesheet" href="demo.css">
+    <link rel="stylesheet" href="../demo.css">
   </head>
   <body>
     <cr-action-menu-demo></cr-action-menu-demo>
-    <script src="cr_action_menu_demo_component.js" type="module"></script>
+    <script src="cr_action_menu_demo.js" type="module"></script>
   </body>
 </html>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_checkbox_demo.html b/chrome/browser/resources/webui_gallery/demos/cr_checkbox_demo.html
index 96c3cde..09bc800 100644
--- a/chrome/browser/resources/webui_gallery/demos/cr_checkbox_demo.html
+++ b/chrome/browser/resources/webui_gallery/demos/cr_checkbox_demo.html
@@ -20,7 +20,7 @@
       </template>
     </dom-bind>
 
-    <script src="chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js"
+    <script src="//resources/cr_elements/cr_checkbox/cr_checkbox.js"
         type="module"></script>
   </body>
 </html>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_dialog_demo_component.html b/chrome/browser/resources/webui_gallery/demos/cr_dialog/cr_dialog_demo.html
similarity index 97%
rename from chrome/browser/resources/webui_gallery/demos/cr_dialog_demo_component.html
rename to chrome/browser/resources/webui_gallery/demos/cr_dialog/cr_dialog_demo.html
index 600ef473..d71198cd 100644
--- a/chrome/browser/resources/webui_gallery/demos/cr_dialog_demo_component.html
+++ b/chrome/browser/resources/webui_gallery/demos/cr_dialog/cr_dialog_demo.html
@@ -1,4 +1,4 @@
-<link rel="stylesheet" href="demo.css">
+<link rel="stylesheet" href="../demo.css">
 
 <style>
   cr-input:first-of-type {
@@ -75,4 +75,4 @@
       Dialogs also have a slot for text or other elements in the footer.
     </div>
   </cr-dialog>
-</template>
\ No newline at end of file
+</template>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_dialog_demo_component.ts b/chrome/browser/resources/webui_gallery/demos/cr_dialog/cr_dialog_demo.ts
similarity index 73%
rename from chrome/browser/resources/webui_gallery/demos/cr_dialog_demo_component.ts
rename to chrome/browser/resources/webui_gallery/demos/cr_dialog/cr_dialog_demo.ts
index 32fbe87..f905a17 100644
--- a/chrome/browser/resources/webui_gallery/demos/cr_dialog_demo_component.ts
+++ b/chrome/browser/resources/webui_gallery/demos/cr_dialog/cr_dialog_demo.ts
@@ -2,24 +2,24 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'chrome://resources/cr_elements/cr_button/cr_button.js';
-import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js';
-import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js';
-import 'chrome://resources/cr_elements/cr_input/cr_input.js';
-import 'chrome://resources/cr_elements/cr_shared_vars.css.js';
+import '//resources/cr_elements/cr_button/cr_button.js';
+import '//resources/cr_elements/cr_dialog/cr_dialog.js';
+import '//resources/cr_elements/cr_checkbox/cr_checkbox.js';
+import '//resources/cr_elements/cr_input/cr_input.js';
+import '//resources/cr_elements/cr_shared_vars.css.js';
 
+import {CrDialogElement} from '//resources/cr_elements/cr_dialog/cr_dialog.js';
 import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js';
 
-import {getTemplate} from './cr_dialog_demo_component.html.js';
+import {getTemplate} from './cr_dialog_demo.html.js';
 
-interface CrDialogDemoComponent {
+interface CrDialogDemoElement {
   $: {
     dialog: CrDialogElement,
   };
 }
 
-class CrDialogDemoComponent extends PolymerElement {
+class CrDialogDemoElement extends PolymerElement {
   static get is() {
     return 'cr-dialog-demo';
   }
@@ -86,4 +86,4 @@
   }
 }
 
-customElements.define(CrDialogDemoComponent.is, CrDialogDemoComponent);
+customElements.define(CrDialogDemoElement.is, CrDialogDemoElement);
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_dialog/index.html b/chrome/browser/resources/webui_gallery/demos/cr_dialog/index.html
new file mode 100644
index 0000000..6d301d2
--- /dev/null
+++ b/chrome/browser/resources/webui_gallery/demos/cr_dialog/index.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>cr-dialog demo</title>
+    <link rel="stylesheet" href="../demo.css">
+  </head>
+  <body>
+    <cr-dialog-demo></cr-dialog-demo>
+    <script src="cr_dialog_demo.js" type="module"></script>
+  </body>
+</html>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_dialog_demo.html b/chrome/browser/resources/webui_gallery/demos/cr_dialog_demo.html
deleted file mode 100644
index 220f90ab..0000000
--- a/chrome/browser/resources/webui_gallery/demos/cr_dialog_demo.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>cr-dialog demo</title>
-    <link rel="stylesheet" href="demo.css">
-  </head>
-  <body>
-    <cr-dialog-demo></cr-dialog-demo>
-    <script src="cr_dialog_demo_component.js" type="module"></script>
-  </body>
-</html>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_icons/cr_icons_demo.html b/chrome/browser/resources/webui_gallery/demos/cr_icons/cr_icons_demo.html
index 557b79e..99413df 100644
--- a/chrome/browser/resources/webui_gallery/demos/cr_icons/cr_icons_demo.html
+++ b/chrome/browser/resources/webui_gallery/demos/cr_icons/cr_icons_demo.html
@@ -1,12 +1,99 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>cr-icons demo</title>
-    <link rel="stylesheet" href="../demo.css">
-  </head>
-  <body>
-    <cr-icons-demo></cr-icons-demo>
-    <script src="cr_icons_demo_component.js" type="module"></script>
-  </body>
-</html>
+<link rel="stylesheet" href="../demo.css">
+<style include="cr-icons">
+  .icons {
+    display: grid;
+    font-size: 11px;
+    gap: 12px;
+    grid-auto-rows: 75px;
+    grid-template-columns: repeat(auto-fill, 75px);
+    text-align: center;
+    width: 100%;
+  }
+
+  .icon {
+    align-items: center;
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+  }
+
+  .icon iron-icon,
+  .icon .cr-icon {
+    margin-block-end: 12px;
+  }
+
+  .label {
+    height: 30%;
+  }
+
+  cr-input {
+    --cr-input-error-display: none;
+  }
+</style>
+
+<h1>cr iron-icons</h1>
+<div class="demos">
+  <div>Commonly used iron-icons across WebUI built with SVG.</div>
+  <div class="icons" style$="
+      --iron-icon-fill-color: [[iconColor_]];
+      --iron-icon-height: [[iconSize_]]px;
+      --iron-icon-width: [[iconSize_]]px;
+  ">
+    <template is="dom-repeat" items="[[ironIcons_]]" as="icon">
+      <div class="icon">
+        <iron-icon icon="[[icon]]"></iron-icon>
+        <div class="label">[[icon]]</div>
+      </div>
+    </template>
+  </div>
+</div>
+
+<h1>Custom iron-icons</h1>
+<div class="demos">
+  <div>An example of a custom iconset for an app using iron-iconset-svg.</div>
+  <iron-iconset-svg name="desserts">
+    <svg>
+      <defs>
+        <g id="cake"><path d="M4 22q-.425 0-.712-.288Q3 21.425 3 21v-5q0-.825.587-1.413Q4.175 14 5 14v-4q0-.825.588-1.413Q6.175 8 7 8h4V6.55q-.45-.3-.725-.725Q10 5.4 10 4.8q0-.375.15-.738.15-.362.45-.662L12 2l1.4 1.4q.3.3.45.662.15.363.15.738 0 .6-.275 1.025-.275.425-.725.725V8h4q.825 0 1.413.587Q19 9.175 19 10v4q.825 0 1.413.587Q21 15.175 21 16v5q0 .425-.288.712Q20.425 22 20 22Zm3-8h10v-4H7Zm-2 6h14v-4H5Zm2-6h10Zm-2 6h14Zm14-6H5h14Z"></g>
+      </defs>
+    </svg>
+  </iron-iconset-svg>
+  <div class="icons" style$="
+      --iron-icon-fill-color: [[iconColor_]];
+      --iron-icon-height: [[iconSize_]]px;
+      --iron-icon-width: [[iconSize_]]px;
+  ">
+    <div class="icon">
+      <iron-icon icon="desserts:cake"></iron-icon>
+      <div class="label">desserts:cake</div>
+    </div>
+  </div>
+</div>
+
+<h1>cr-icons CSS classes</h1>
+<div class="demos">
+  <div>CSS classes to display icons, typically for cr-icon-button.</div>
+  <div class="icons" style$="
+      --cr-icon-color: [[iconColor_]];
+      --cr-icon-ripple-size: [[iconSize_]]px;
+      --cr-icon-size: [[iconSize_]]px;
+  ">
+    <template is="dom-repeat" items="[[crIcons_]]" as="icon">
+      <div class="icon">
+        <div class$="cr-icon no-overlap [[icon]]"></div>
+        <div class="label">.[[icon]]</div>
+      </div>
+    </template>
+  </div>
+</div>
+
+<h1>Custom controls</h1>
+<div class="demos">
+  <cr-input type="number" min="12" max="128" value="{{iconSize_}}"
+      label="Icon size"></cr-input>
+
+  <label>
+    <input type="color" value="[[iconColor_]]" on-input="onIconColorInput_">
+    Icon fill color
+  </label>
+</div>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_icons/cr_icons_demo_component.ts b/chrome/browser/resources/webui_gallery/demos/cr_icons/cr_icons_demo.ts
similarity index 91%
rename from chrome/browser/resources/webui_gallery/demos/cr_icons/cr_icons_demo_component.ts
rename to chrome/browser/resources/webui_gallery/demos/cr_icons/cr_icons_demo.ts
index fe21a71d..da1c68f 100644
--- a/chrome/browser/resources/webui_gallery/demos/cr_icons/cr_icons_demo_component.ts
+++ b/chrome/browser/resources/webui_gallery/demos/cr_icons/cr_icons_demo.ts
@@ -11,9 +11,9 @@
 import {IronIconsetSvgElement} from '//resources/polymer/v3_0/iron-iconset-svg/iron-iconset-svg.js';
 import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-import {getTemplate} from './cr_icons_demo_component.html.js';
+import {getTemplate} from './cr_icons_demo.html.js';
 
-class CrIconsDemoComponent extends PolymerElement {
+class CrIconsDemoElement extends PolymerElement {
   static get is() {
     return 'cr-icons-demo';
   }
@@ -66,4 +66,4 @@
   }
 }
 
-customElements.define(CrIconsDemoComponent.is, CrIconsDemoComponent);
+customElements.define(CrIconsDemoElement.is, CrIconsDemoElement);
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_icons/cr_icons_demo_component.html b/chrome/browser/resources/webui_gallery/demos/cr_icons/cr_icons_demo_component.html
deleted file mode 100644
index 99413df..0000000
--- a/chrome/browser/resources/webui_gallery/demos/cr_icons/cr_icons_demo_component.html
+++ /dev/null
@@ -1,99 +0,0 @@
-<link rel="stylesheet" href="../demo.css">
-<style include="cr-icons">
-  .icons {
-    display: grid;
-    font-size: 11px;
-    gap: 12px;
-    grid-auto-rows: 75px;
-    grid-template-columns: repeat(auto-fill, 75px);
-    text-align: center;
-    width: 100%;
-  }
-
-  .icon {
-    align-items: center;
-    display: flex;
-    flex-direction: column;
-    justify-content: center;
-  }
-
-  .icon iron-icon,
-  .icon .cr-icon {
-    margin-block-end: 12px;
-  }
-
-  .label {
-    height: 30%;
-  }
-
-  cr-input {
-    --cr-input-error-display: none;
-  }
-</style>
-
-<h1>cr iron-icons</h1>
-<div class="demos">
-  <div>Commonly used iron-icons across WebUI built with SVG.</div>
-  <div class="icons" style$="
-      --iron-icon-fill-color: [[iconColor_]];
-      --iron-icon-height: [[iconSize_]]px;
-      --iron-icon-width: [[iconSize_]]px;
-  ">
-    <template is="dom-repeat" items="[[ironIcons_]]" as="icon">
-      <div class="icon">
-        <iron-icon icon="[[icon]]"></iron-icon>
-        <div class="label">[[icon]]</div>
-      </div>
-    </template>
-  </div>
-</div>
-
-<h1>Custom iron-icons</h1>
-<div class="demos">
-  <div>An example of a custom iconset for an app using iron-iconset-svg.</div>
-  <iron-iconset-svg name="desserts">
-    <svg>
-      <defs>
-        <g id="cake"><path d="M4 22q-.425 0-.712-.288Q3 21.425 3 21v-5q0-.825.587-1.413Q4.175 14 5 14v-4q0-.825.588-1.413Q6.175 8 7 8h4V6.55q-.45-.3-.725-.725Q10 5.4 10 4.8q0-.375.15-.738.15-.362.45-.662L12 2l1.4 1.4q.3.3.45.662.15.363.15.738 0 .6-.275 1.025-.275.425-.725.725V8h4q.825 0 1.413.587Q19 9.175 19 10v4q.825 0 1.413.587Q21 15.175 21 16v5q0 .425-.288.712Q20.425 22 20 22Zm3-8h10v-4H7Zm-2 6h14v-4H5Zm2-6h10Zm-2 6h14Zm14-6H5h14Z"></g>
-      </defs>
-    </svg>
-  </iron-iconset-svg>
-  <div class="icons" style$="
-      --iron-icon-fill-color: [[iconColor_]];
-      --iron-icon-height: [[iconSize_]]px;
-      --iron-icon-width: [[iconSize_]]px;
-  ">
-    <div class="icon">
-      <iron-icon icon="desserts:cake"></iron-icon>
-      <div class="label">desserts:cake</div>
-    </div>
-  </div>
-</div>
-
-<h1>cr-icons CSS classes</h1>
-<div class="demos">
-  <div>CSS classes to display icons, typically for cr-icon-button.</div>
-  <div class="icons" style$="
-      --cr-icon-color: [[iconColor_]];
-      --cr-icon-ripple-size: [[iconSize_]]px;
-      --cr-icon-size: [[iconSize_]]px;
-  ">
-    <template is="dom-repeat" items="[[crIcons_]]" as="icon">
-      <div class="icon">
-        <div class$="cr-icon no-overlap [[icon]]"></div>
-        <div class="label">.[[icon]]</div>
-      </div>
-    </template>
-  </div>
-</div>
-
-<h1>Custom controls</h1>
-<div class="demos">
-  <cr-input type="number" min="12" max="128" value="{{iconSize_}}"
-      label="Icon size"></cr-input>
-
-  <label>
-    <input type="color" value="[[iconColor_]]" on-input="onIconColorInput_">
-    Icon fill color
-  </label>
-</div>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_icons/index.html b/chrome/browser/resources/webui_gallery/demos/cr_icons/index.html
new file mode 100644
index 0000000..8d1882d6
--- /dev/null
+++ b/chrome/browser/resources/webui_gallery/demos/cr_icons/index.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>cr-icons demo</title>
+    <link rel="stylesheet" href="../demo.css">
+  </head>
+  <body>
+    <cr-icons-demo></cr-icons-demo>
+    <script src="cr_icons_demo.js" type="module"></script>
+  </body>
+</html>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_input/cr_input_demo.html b/chrome/browser/resources/webui_gallery/demos/cr_input/cr_input_demo.html
index 12f83f00..0bdc173 100644
--- a/chrome/browser/resources/webui_gallery/demos/cr_input/cr_input_demo.html
+++ b/chrome/browser/resources/webui_gallery/demos/cr_input/cr_input_demo.html
@@ -1,12 +1,105 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>cr-input demo</title>
-    <link rel="stylesheet" href="../demo.css">
-  </head>
-  <body>
-    <cr-input-demo></cr-input-demo>
-    <script src="cr_input_demo_component.js" type="module"></script>
-  </body>
-</html>
+<link rel="stylesheet" href="../demo.css">
+<style include="cr-hidden-style cr-icons">
+  cr-input {
+    max-width: 400px;
+    width: 100%;
+  }
+
+  .cr-icon {
+    --cr-icon-button-margin-start: 0;
+  }
+
+  .no-error {
+    --cr-input-error-display: none;
+  }
+
+  .icon-cancel {
+    --cr-icon-button-icon-size: 16px;
+    --cr-icon-button-margin-end: 6px;
+    --cr-icon-button-size: 24px;
+  }
+
+  .domain-name {
+    padding-inline-end: 8px;
+  }
+</style>
+
+<h1>cr-input</h1>
+
+<div class="demos">
+  <cr-input
+      class="no-error"
+      type="text"
+      label="Standard input"
+      placeholder="Placeholder text"
+      value="{{textValue_}}">
+  </cr-input>
+
+  <cr-input
+      class="no-error"
+      type="search"
+      placeholder="Search a query"
+      value="{{searchValue_}}">
+    <div slot="inline-prefix" class="cr-icon icon-search" alt=""></div>
+    <cr-icon-button class="icon-cancel"
+        hidden$="[[!searchValue_]]" slot="inline-suffix"
+        on-click="onClearSearchClick_"
+        title="Clear search">
+    </cr-icon-button>
+  </cr-input>
+
+  <cr-input
+      class="no-error"
+      label="Email address"
+      type="text"
+      placeholder="username"
+      value="{{emailValue_}}">
+    <div slot="inline-suffix" class="domain-name">@chromium.org</div>
+  </cr-input>
+
+  <cr-input
+      id="numberInput"
+      label="Number input"
+      type="number"
+      min="5"
+      max="200"
+      placeholder="A number between 5 and 200"
+      error-message="Number needs to be between 5 and 200"
+      value="{{numberValue_}}">
+    <cr-button slot="suffix" on-click="onValidateClick_">Validate</cr-button>
+  </cr-input>
+
+  <cr-input
+      label="Auto-validating pin"
+      type="password"
+      placeholder="Enter a pin of 4 digits"
+      pattern="[0-9]{4}"
+      error-message="Pin must be 4 digits"
+      value="{{pinValue_}}"
+      auto-validate>
+  </cr-input>
+
+  <cr-input
+      class="no-error"
+      type="text"
+      label="Disabled input"
+      disabled
+      value="The value cannot be changed">
+  </cr-input>
+
+  <cr-input
+      class="no-error"
+      type="text"
+      label="Readonly input"
+      readonly
+      value="The value cannot be changed">
+  </cr-input>
+
+  <div>
+    <div>Text input value: [[textValue_]]</div>
+    <div>Search input value: [[searchValue_]]</div>
+    <div>Email input value: [[emailValue_]]</div>
+    <div>Number input value: [[numberValue_]]</div>
+    <div>Pin input value: [[pinValue_]]</div>
+  </div>
+</div>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_input/cr_input_demo.ts b/chrome/browser/resources/webui_gallery/demos/cr_input/cr_input_demo.ts
new file mode 100644
index 0000000..6018e498
--- /dev/null
+++ b/chrome/browser/resources/webui_gallery/demos/cr_input/cr_input_demo.ts
@@ -0,0 +1,56 @@
+// 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 '//resources/cr_elements/cr_button/cr_button.js';
+import '//resources/cr_elements/cr_icon_button/cr_icon_button.js';
+import '//resources/cr_elements/cr_input/cr_input.js';
+import '//resources/cr_elements/cr_icons.css.js';
+import '//resources/cr_elements/cr_hidden_style.css.js';
+
+import {CrInputElement} from '//resources/cr_elements/cr_input/cr_input.js';
+import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {getTemplate} from './cr_input_demo.html.js';
+
+interface CrInputDemoElement {
+  $: {
+    numberInput: CrInputElement,
+  };
+}
+
+class CrInputDemoElement extends PolymerElement {
+  static get is() {
+    return 'cr-input-demo';
+  }
+
+  static get template() {
+    return getTemplate();
+  }
+
+  static get properties() {
+    return {
+      emailValue_: String,
+      numberValue_: String,
+      pinValue_: String,
+      searchValue_: String,
+      textValue_: String,
+    };
+  }
+
+  private emailValue_: string;
+  private numberValue_: string;
+  private pinValue_: string;
+  private searchValue_: string;
+  private textValue_: string;
+
+  private onClearSearchClick_() {
+    this.searchValue_ = '';
+  }
+
+  private onValidateClick_() {
+    this.$.numberInput.validate();
+  }
+}
+
+customElements.define(CrInputDemoElement.is, CrInputDemoElement);
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_input/cr_input_demo_component.html b/chrome/browser/resources/webui_gallery/demos/cr_input/cr_input_demo_component.html
deleted file mode 100644
index 0bdc173..0000000
--- a/chrome/browser/resources/webui_gallery/demos/cr_input/cr_input_demo_component.html
+++ /dev/null
@@ -1,105 +0,0 @@
-<link rel="stylesheet" href="../demo.css">
-<style include="cr-hidden-style cr-icons">
-  cr-input {
-    max-width: 400px;
-    width: 100%;
-  }
-
-  .cr-icon {
-    --cr-icon-button-margin-start: 0;
-  }
-
-  .no-error {
-    --cr-input-error-display: none;
-  }
-
-  .icon-cancel {
-    --cr-icon-button-icon-size: 16px;
-    --cr-icon-button-margin-end: 6px;
-    --cr-icon-button-size: 24px;
-  }
-
-  .domain-name {
-    padding-inline-end: 8px;
-  }
-</style>
-
-<h1>cr-input</h1>
-
-<div class="demos">
-  <cr-input
-      class="no-error"
-      type="text"
-      label="Standard input"
-      placeholder="Placeholder text"
-      value="{{textValue_}}">
-  </cr-input>
-
-  <cr-input
-      class="no-error"
-      type="search"
-      placeholder="Search a query"
-      value="{{searchValue_}}">
-    <div slot="inline-prefix" class="cr-icon icon-search" alt=""></div>
-    <cr-icon-button class="icon-cancel"
-        hidden$="[[!searchValue_]]" slot="inline-suffix"
-        on-click="onClearSearchClick_"
-        title="Clear search">
-    </cr-icon-button>
-  </cr-input>
-
-  <cr-input
-      class="no-error"
-      label="Email address"
-      type="text"
-      placeholder="username"
-      value="{{emailValue_}}">
-    <div slot="inline-suffix" class="domain-name">@chromium.org</div>
-  </cr-input>
-
-  <cr-input
-      id="numberInput"
-      label="Number input"
-      type="number"
-      min="5"
-      max="200"
-      placeholder="A number between 5 and 200"
-      error-message="Number needs to be between 5 and 200"
-      value="{{numberValue_}}">
-    <cr-button slot="suffix" on-click="onValidateClick_">Validate</cr-button>
-  </cr-input>
-
-  <cr-input
-      label="Auto-validating pin"
-      type="password"
-      placeholder="Enter a pin of 4 digits"
-      pattern="[0-9]{4}"
-      error-message="Pin must be 4 digits"
-      value="{{pinValue_}}"
-      auto-validate>
-  </cr-input>
-
-  <cr-input
-      class="no-error"
-      type="text"
-      label="Disabled input"
-      disabled
-      value="The value cannot be changed">
-  </cr-input>
-
-  <cr-input
-      class="no-error"
-      type="text"
-      label="Readonly input"
-      readonly
-      value="The value cannot be changed">
-  </cr-input>
-
-  <div>
-    <div>Text input value: [[textValue_]]</div>
-    <div>Search input value: [[searchValue_]]</div>
-    <div>Email input value: [[emailValue_]]</div>
-    <div>Number input value: [[numberValue_]]</div>
-    <div>Pin input value: [[pinValue_]]</div>
-  </div>
-</div>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_input/cr_input_demo_component.ts b/chrome/browser/resources/webui_gallery/demos/cr_input/cr_input_demo_component.ts
deleted file mode 100644
index cdc894bb..0000000
--- a/chrome/browser/resources/webui_gallery/demos/cr_input/cr_input_demo_component.ts
+++ /dev/null
@@ -1,56 +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 'chrome://resources/cr_elements/cr_button/cr_button.js';
-import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js';
-import 'chrome://resources/cr_elements/cr_input/cr_input.js';
-import 'chrome://resources/cr_elements/cr_icons.css.js';
-import 'chrome://resources/cr_elements/cr_hidden_style.css.js';
-
-import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {CrInputElement} from 'chrome://resources/cr_elements/cr_input/cr_input.js';
-
-import {getTemplate} from './cr_input_demo_component.html.js';
-
-interface CrInputDemoComponent {
-  $: {
-    numberInput: CrInputElement,
-  };
-}
-
-class CrInputDemoComponent extends PolymerElement {
-  static get is() {
-    return 'cr-input-demo';
-  }
-
-  static get template() {
-    return getTemplate();
-  }
-
-  static get properties() {
-    return {
-      emailValue_: String,
-      numberValue_: String,
-      pinValue_: String,
-      searchValue_: String,
-      textValue_: String,
-    };
-  }
-
-  private emailValue_: string;
-  private numberValue_: string;
-  private pinValue_: string;
-  private searchValue_: string;
-  private textValue_: string;
-
-  private onClearSearchClick_() {
-    this.searchValue_ = '';
-  }
-
-  private onValidateClick_() {
-    this.$.numberInput.validate();
-  }
-}
-
-customElements.define(CrInputDemoComponent.is, CrInputDemoComponent);
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_input/index.html b/chrome/browser/resources/webui_gallery/demos/cr_input/index.html
new file mode 100644
index 0000000..831f5a2
--- /dev/null
+++ b/chrome/browser/resources/webui_gallery/demos/cr_input/index.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>cr-input demo</title>
+    <link rel="stylesheet" href="../demo.css">
+  </head>
+  <body>
+    <cr-input-demo></cr-input-demo>
+    <script src="cr_input_demo.js" type="module"></script>
+  </body>
+</html>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_radio_demo.html b/chrome/browser/resources/webui_gallery/demos/cr_radio_demo.html
index e9567b59..051bc4a22 100644
--- a/chrome/browser/resources/webui_gallery/demos/cr_radio_demo.html
+++ b/chrome/browser/resources/webui_gallery/demos/cr_radio_demo.html
@@ -23,9 +23,9 @@
       </template>
     </dom-bind>
 
-    <script src="chrome://resources/cr_elements/cr_radio_group/cr_radio_group.js"
+    <script src="//resources/cr_elements/cr_radio_group/cr_radio_group.js"
         type="module"></script>
-    <script src="chrome://resources/cr_elements/cr_radio_button/cr_radio_button.js"
+    <script src="//resources/cr_elements/cr_radio_button/cr_radio_button.js"
         type="module"></script>
   </body>
 </html>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_slider/cr_slider_demo.html b/chrome/browser/resources/webui_gallery/demos/cr_slider/cr_slider_demo.html
index e4ebf4a..92408cbd 100644
--- a/chrome/browser/resources/webui_gallery/demos/cr_slider/cr_slider_demo.html
+++ b/chrome/browser/resources/webui_gallery/demos/cr_slider/cr_slider_demo.html
@@ -1,12 +1,33 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>cr-slider demo</title>
-    <link rel="stylesheet" href="../demo.css">
-  </head>
-  <body>
-    <cr-slider-demo></cr-slider-demo>
-    <script src="cr_slider_demo_component.js" type="module"></script>
-  </body>
-</html>
+<link rel="stylesheet" href="../demo.css">
+<style>
+  cr-slider {
+    width: 200px;
+  }
+</style>
+
+<h1>cr-slider</h1>
+
+<h2>Indiscrete</h2>
+<div class="demos">
+  <cr-slider id="basicSlider" min="0" max="20" value="[[basicValue_]]"
+      on-cr-slider-value-changed="onBasicValueChanged_">
+  </cr-slider>
+  <div>Value of slider: [[basicValue_]]</div>
+</div>
+
+<h2>5 ticks, increments of 5</h2>
+<div class="demos">
+  <cr-slider id="tickedSlider" ticks="[[ticks_]]"
+      marker-count="[[getMarkerCount_(showMarkers_)]]"
+      value="[[tickedValue_]]"
+      on-cr-slider-value-changed="onTickedValueChanged_">
+  </cr-slider>
+  <div>Value of slider, the index of selected tick: [[tickedValue_]]</div>
+  <div>Value of selected tick: [[getTickValue_(tickedValue_)]]</div>
+  <cr-checkbox checked="{{showMarkers_}}">Show markers</cr-checkbox>
+</div>
+
+<h2>Disabled</h2>
+<div class="demos">
+  <cr-slider min="0" max="20" value="12" disabled></cr-slider>
+</div>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_slider/cr_slider_demo_component.ts b/chrome/browser/resources/webui_gallery/demos/cr_slider/cr_slider_demo.ts
similarity index 76%
rename from chrome/browser/resources/webui_gallery/demos/cr_slider/cr_slider_demo_component.ts
rename to chrome/browser/resources/webui_gallery/demos/cr_slider/cr_slider_demo.ts
index 9fc6bda..ebeadfef 100644
--- a/chrome/browser/resources/webui_gallery/demos/cr_slider/cr_slider_demo_component.ts
+++ b/chrome/browser/resources/webui_gallery/demos/cr_slider/cr_slider_demo.ts
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js';
-import 'chrome://resources/cr_elements/cr_slider/cr_slider.js';
+import '//resources/cr_elements/cr_checkbox/cr_checkbox.js';
+import '//resources/cr_elements/cr_slider/cr_slider.js';
 
+import {CrSliderElement, SliderTick} from '//resources/cr_elements/cr_slider/cr_slider.js';
 import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {CrSliderElement, SliderTick} from 'chrome://resources/cr_elements/cr_slider/cr_slider.js';
 
-import {getTemplate} from './cr_slider_demo_component.html.js';
+import {getTemplate} from './cr_slider_demo.html.js';
 
-interface CrSliderDemoComponent {
+interface CrSliderDemoElement {
   $: {
     basicSlider: CrSliderElement,
     tickedSlider: CrSliderElement,
@@ -30,7 +30,7 @@
   return ticks;
 }
 
-class CrSliderDemoComponent extends PolymerElement {
+class CrSliderDemoElement extends PolymerElement {
   static get is() {
     return 'cr-slider-demo';
   }
@@ -75,4 +75,4 @@
   }
 }
 
-customElements.define(CrSliderDemoComponent.is, CrSliderDemoComponent);
+customElements.define(CrSliderDemoElement.is, CrSliderDemoElement);
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_slider/cr_slider_demo_component.html b/chrome/browser/resources/webui_gallery/demos/cr_slider/cr_slider_demo_component.html
deleted file mode 100644
index 92408cbd..0000000
--- a/chrome/browser/resources/webui_gallery/demos/cr_slider/cr_slider_demo_component.html
+++ /dev/null
@@ -1,33 +0,0 @@
-<link rel="stylesheet" href="../demo.css">
-<style>
-  cr-slider {
-    width: 200px;
-  }
-</style>
-
-<h1>cr-slider</h1>
-
-<h2>Indiscrete</h2>
-<div class="demos">
-  <cr-slider id="basicSlider" min="0" max="20" value="[[basicValue_]]"
-      on-cr-slider-value-changed="onBasicValueChanged_">
-  </cr-slider>
-  <div>Value of slider: [[basicValue_]]</div>
-</div>
-
-<h2>5 ticks, increments of 5</h2>
-<div class="demos">
-  <cr-slider id="tickedSlider" ticks="[[ticks_]]"
-      marker-count="[[getMarkerCount_(showMarkers_)]]"
-      value="[[tickedValue_]]"
-      on-cr-slider-value-changed="onTickedValueChanged_">
-  </cr-slider>
-  <div>Value of slider, the index of selected tick: [[tickedValue_]]</div>
-  <div>Value of selected tick: [[getTickValue_(tickedValue_)]]</div>
-  <cr-checkbox checked="{{showMarkers_}}">Show markers</cr-checkbox>
-</div>
-
-<h2>Disabled</h2>
-<div class="demos">
-  <cr-slider min="0" max="20" value="12" disabled></cr-slider>
-</div>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_slider/index.html b/chrome/browser/resources/webui_gallery/demos/cr_slider/index.html
new file mode 100644
index 0000000..0064969
--- /dev/null
+++ b/chrome/browser/resources/webui_gallery/demos/cr_slider/index.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>cr-slider demo</title>
+    <link rel="stylesheet" href="../demo.css">
+  </head>
+  <body>
+    <cr-slider-demo></cr-slider-demo>
+    <script src="cr_slider_demo.js" type="module"></script>
+  </body>
+</html>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_tab_box/cr_tab_box_demo.html b/chrome/browser/resources/webui_gallery/demos/cr_tab_box/cr_tab_box_demo.html
index 5ec7c07..f019f2c 100644
--- a/chrome/browser/resources/webui_gallery/demos/cr_tab_box/cr_tab_box_demo.html
+++ b/chrome/browser/resources/webui_gallery/demos/cr_tab_box/cr_tab_box_demo.html
@@ -1,12 +1,56 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>cr-tab-box demo</title>
-    <link rel="stylesheet" href="../demo.css">
-  </head>
-  <body>
-    <cr-tab-box-demo></cr-tab-box-demo>
-    <script src="cr_tab_box_demo_component.js" type="module"></script>
-  </body>
-</html>
+<link rel="stylesheet" href="../demo.css">
+<style>
+  div[slot='panel'] {
+    padding: 90px 0;
+    width: 100%;
+  }
+
+  button {
+    background: white;
+    border: 1px solid #c8c8c8;
+    color: #646464;
+    line-height: 24px;
+    margin-inline-end: 10px;
+  }
+
+  button:hover {
+    color: black;
+  }
+
+  button:active {
+    box-shadow: 0 1px 2px 0 rgba(200, 200, 200, .3),
+        0 3px 6px 2px rgba(200, 200, 200, .15);
+    color: black;
+  }
+
+  span {
+    font-family: sans-serif;
+    font-size: 10pt;
+  }
+</style>
+<h1>cr-tab-box</h1>
+<div class="demos">
+  <cr-tab-box>
+    <div slot="tab">Tab 1</div>
+    <div slot="tab">Tab 2</div>
+    <div slot="tab">Tab 3</div>
+    <div slot="panel">Tab 1</div>
+    <div slot="panel">Tab 2</div>
+    <div slot="panel">Tab 3</div>
+  </cr-tab-box>
+  <div class="buttons">
+    <button class="add-tab">Add</button>
+    <button class="add-tab-one">Add At 1</button>
+    <button class="select-tab-one">Select At 1</button>
+  </div>
+  <div class="info">
+    <span>Tab Count: </span>
+    <span class="tab-count"></span>
+    <span>, Selected Tab: </span>
+    <span class="selected-tab">0</span>
+  </div>
+</div>
+<template id="template">
+  <div slot="tab"></div>
+  <div slot="panel"></div>
+</template>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_tab_box/cr_tab_box_demo_component.ts b/chrome/browser/resources/webui_gallery/demos/cr_tab_box/cr_tab_box_demo.ts
similarity index 85%
rename from chrome/browser/resources/webui_gallery/demos/cr_tab_box/cr_tab_box_demo_component.ts
rename to chrome/browser/resources/webui_gallery/demos/cr_tab_box/cr_tab_box_demo.ts
index 1f3ca08..d63af8c8 100644
--- a/chrome/browser/resources/webui_gallery/demos/cr_tab_box/cr_tab_box_demo_component.ts
+++ b/chrome/browser/resources/webui_gallery/demos/cr_tab_box/cr_tab_box_demo.ts
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'chrome://resources/cr_elements/cr_tab_box/cr_tab_box.js';
+import '//resources/cr_elements/cr_tab_box/cr_tab_box.js';
 
-import {CrTabBoxElement} from 'chrome://resources/cr_elements/cr_tab_box/cr_tab_box.js';
-import {assert} from 'chrome://resources/js/assert_ts.js';
-import {CustomElement} from 'chrome://resources/js/custom_element.js';
+import {CrTabBoxElement} from '//resources/cr_elements/cr_tab_box/cr_tab_box.js';
+import {assert} from '//resources/js/assert_ts.js';
+import {CustomElement} from '//resources/js/custom_element.js';
 
-import {getTemplate} from './cr_tab_box_demo_component.html.js';
+import {getTemplate} from './cr_tab_box_demo.html.js';
 
-class CrTabBoxDemoComponent extends CustomElement {
+class CrTabBoxDemoElement extends CustomElement {
   static override get template() {
     return getTemplate();
   }
@@ -91,4 +91,4 @@
   }
 }
 
-customElements.define('cr-tab-box-demo', CrTabBoxDemoComponent);
+customElements.define('cr-tab-box-demo', CrTabBoxDemoElement);
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_tab_box/cr_tab_box_demo_component.html b/chrome/browser/resources/webui_gallery/demos/cr_tab_box/cr_tab_box_demo_component.html
deleted file mode 100644
index f019f2c..0000000
--- a/chrome/browser/resources/webui_gallery/demos/cr_tab_box/cr_tab_box_demo_component.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<link rel="stylesheet" href="../demo.css">
-<style>
-  div[slot='panel'] {
-    padding: 90px 0;
-    width: 100%;
-  }
-
-  button {
-    background: white;
-    border: 1px solid #c8c8c8;
-    color: #646464;
-    line-height: 24px;
-    margin-inline-end: 10px;
-  }
-
-  button:hover {
-    color: black;
-  }
-
-  button:active {
-    box-shadow: 0 1px 2px 0 rgba(200, 200, 200, .3),
-        0 3px 6px 2px rgba(200, 200, 200, .15);
-    color: black;
-  }
-
-  span {
-    font-family: sans-serif;
-    font-size: 10pt;
-  }
-</style>
-<h1>cr-tab-box</h1>
-<div class="demos">
-  <cr-tab-box>
-    <div slot="tab">Tab 1</div>
-    <div slot="tab">Tab 2</div>
-    <div slot="tab">Tab 3</div>
-    <div slot="panel">Tab 1</div>
-    <div slot="panel">Tab 2</div>
-    <div slot="panel">Tab 3</div>
-  </cr-tab-box>
-  <div class="buttons">
-    <button class="add-tab">Add</button>
-    <button class="add-tab-one">Add At 1</button>
-    <button class="select-tab-one">Select At 1</button>
-  </div>
-  <div class="info">
-    <span>Tab Count: </span>
-    <span class="tab-count"></span>
-    <span>, Selected Tab: </span>
-    <span class="selected-tab">0</span>
-  </div>
-</div>
-<template id="template">
-  <div slot="tab"></div>
-  <div slot="panel"></div>
-</template>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_tab_box/index.html b/chrome/browser/resources/webui_gallery/demos/cr_tab_box/index.html
new file mode 100644
index 0000000..d17ddb3
--- /dev/null
+++ b/chrome/browser/resources/webui_gallery/demos/cr_tab_box/index.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>cr-tab-box demo</title>
+    <link rel="stylesheet" href="../demo.css">
+  </head>
+  <body>
+    <cr-tab-box-demo></cr-tab-box-demo>
+    <script src="cr_tab_box_demo.js" type="module"></script>
+  </body>
+</html>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_tabs/cr_tabs_demo.html b/chrome/browser/resources/webui_gallery/demos/cr_tabs/cr_tabs_demo.html
index 7d435df9..e2c1a83b 100644
--- a/chrome/browser/resources/webui_gallery/demos/cr_tabs/cr_tabs_demo.html
+++ b/chrome/browser/resources/webui_gallery/demos/cr_tabs/cr_tabs_demo.html
@@ -1,12 +1,39 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>cr-tabs demo</title>
-    <link rel="stylesheet" href="../demo.css">
-  </head>
-  <body>
-    <cr-tabs-demo></cr-tabs-demo>
-    <script src="cr_tabs_demo_component.js" type="module"></script>
-  </body>
-</html>
+<link rel="stylesheet" href="../demo.css">
+<style>
+  cr-tabs,
+  iron-pages {
+    width: 100%;
+  }
+
+  .tab-contents {
+    align-items: center;
+    display: flex;
+    height: 150px;
+    justify-content: center;
+  }
+</style>
+
+<h1>cr-tabs</h1>
+<div class="demos">
+  <cr-tabs tab-names="[[tabNames_]]" selected="{{selectedTabIndex_}}"></cr-tabs>
+  <iron-pages selected="[[selectedTabIndex_]]">
+    <template is="dom-repeat" items="[[tabNames_]]" as="tabName">
+      <div class="tab-contents">
+        [[tabName]] contents
+      </div>
+    </template>
+  </iron-pages>
+</div>
+
+<div class="demos">
+  <div class="row">
+    <cr-button on-click="onAddClick_">Add</cr-button>
+    <cr-button on-click="onAddAt1Click_">Add at 1</cr-button>
+    <cr-button on-click="onSelectAt1Click_">Select at 1</cr-button>
+  </div>
+</div>
+
+<div>
+  Tab Count: [[tabNames_.length]],
+  Selected Tab: [[selectedTabIndex_]]
+</div>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_tabs/cr_tabs_demo.ts b/chrome/browser/resources/webui_gallery/demos/cr_tabs/cr_tabs_demo.ts
new file mode 100644
index 0000000..5bef7174
--- /dev/null
+++ b/chrome/browser/resources/webui_gallery/demos/cr_tabs/cr_tabs_demo.ts
@@ -0,0 +1,45 @@
+// 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 '//resources/cr_elements/cr_button/cr_button.js';
+import '//resources/cr_elements/cr_tabs/cr_tabs.js';
+import '//resources/polymer/v3_0/iron-pages/iron-pages.js';
+
+import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {getTemplate} from './cr_tabs_demo.html.js';
+
+class CrTabsDemoElement extends PolymerElement {
+  static get is() {
+    return 'cr-tabs-demo';
+  }
+
+  static get template() {
+    return getTemplate();
+  }
+
+  static get properties() {
+    return {
+      selectedTabIndex_: Number,
+      tabNames_: Array,
+    };
+  }
+
+  private selectedTabIndex_ = 0;
+  private tabNames_: string[] = ['Tab 1', 'Tab 2', 'Tab 3'];
+
+  private onAddClick_() {
+    this.push('tabNames_', 'Added');
+  }
+
+  private onAddAt1Click_() {
+    this.splice('tabNames_', 1, 0, 'Added at 1');
+  }
+
+  private onSelectAt1Click_() {
+    this.selectedTabIndex_ = 1;
+  }
+}
+
+customElements.define(CrTabsDemoElement.is, CrTabsDemoElement);
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_tabs/cr_tabs_demo_component.html b/chrome/browser/resources/webui_gallery/demos/cr_tabs/cr_tabs_demo_component.html
deleted file mode 100644
index e2c1a83b..0000000
--- a/chrome/browser/resources/webui_gallery/demos/cr_tabs/cr_tabs_demo_component.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<link rel="stylesheet" href="../demo.css">
-<style>
-  cr-tabs,
-  iron-pages {
-    width: 100%;
-  }
-
-  .tab-contents {
-    align-items: center;
-    display: flex;
-    height: 150px;
-    justify-content: center;
-  }
-</style>
-
-<h1>cr-tabs</h1>
-<div class="demos">
-  <cr-tabs tab-names="[[tabNames_]]" selected="{{selectedTabIndex_}}"></cr-tabs>
-  <iron-pages selected="[[selectedTabIndex_]]">
-    <template is="dom-repeat" items="[[tabNames_]]" as="tabName">
-      <div class="tab-contents">
-        [[tabName]] contents
-      </div>
-    </template>
-  </iron-pages>
-</div>
-
-<div class="demos">
-  <div class="row">
-    <cr-button on-click="onAddClick_">Add</cr-button>
-    <cr-button on-click="onAddAt1Click_">Add at 1</cr-button>
-    <cr-button on-click="onSelectAt1Click_">Select at 1</cr-button>
-  </div>
-</div>
-
-<div>
-  Tab Count: [[tabNames_.length]],
-  Selected Tab: [[selectedTabIndex_]]
-</div>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_tabs/cr_tabs_demo_component.ts b/chrome/browser/resources/webui_gallery/demos/cr_tabs/cr_tabs_demo_component.ts
deleted file mode 100644
index d1134da..0000000
--- a/chrome/browser/resources/webui_gallery/demos/cr_tabs/cr_tabs_demo_component.ts
+++ /dev/null
@@ -1,45 +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 'chrome://resources/cr_elements/cr_button/cr_button.js';
-import 'chrome://resources/cr_elements/cr_tabs/cr_tabs.js';
-import 'chrome://resources/polymer/v3_0/iron-pages/iron-pages.js';
-
-import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {getTemplate} from './cr_tabs_demo_component.html.js';
-
-class CrTabsDemoComponent extends PolymerElement {
-  static get is() {
-    return 'cr-tabs-demo';
-  }
-
-  static get template() {
-    return getTemplate();
-  }
-
-  static get properties() {
-    return {
-      selectedTabIndex_: Number,
-      tabNames_: Array,
-    };
-  }
-
-  private selectedTabIndex_ = 0;
-  private tabNames_: string[] = ['Tab 1', 'Tab 2', 'Tab 3'];
-
-  private onAddClick_() {
-    this.push('tabNames_', 'Added');
-  }
-
-  private onAddAt1Click_() {
-    this.splice('tabNames_', 1, 0, 'Added at 1');
-  }
-
-  private onSelectAt1Click_() {
-    this.selectedTabIndex_ = 1;
-  }
-}
-
-customElements.define(CrTabsDemoComponent.is, CrTabsDemoComponent);
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_tabs/index.html b/chrome/browser/resources/webui_gallery/demos/cr_tabs/index.html
new file mode 100644
index 0000000..41d8dd73
--- /dev/null
+++ b/chrome/browser/resources/webui_gallery/demos/cr_tabs/index.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>cr-tabs demo</title>
+    <link rel="stylesheet" href="../demo.css">
+  </head>
+  <body>
+    <cr-tabs-demo></cr-tabs-demo>
+    <script src="cr_tabs_demo.js" type="module"></script>
+  </body>
+</html>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_toast/cr_toast_demo.html b/chrome/browser/resources/webui_gallery/demos/cr_toast/cr_toast_demo.html
index bb13f5f..68e03dc7 100644
--- a/chrome/browser/resources/webui_gallery/demos/cr_toast/cr_toast_demo.html
+++ b/chrome/browser/resources/webui_gallery/demos/cr_toast/cr_toast_demo.html
@@ -1,15 +1,37 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>cr-toast demo</title>
-    <link rel="stylesheet" href="../demo.css">
-  </head>
-  <body>
-    <cr-toast-demo></cr-toast-demo>
-    <cr-toast-manager duration="5000"></cr-toast-manager>
-    <script src="chrome://resources/cr_elements/cr_toast/cr_toast_manager.js"
-        type="module"></script>
-    <script src="cr_toast_demo_component.js" type="module"></script>
-  </body>
-</html>
+<link rel="stylesheet" href="../demo.css">
+<style>
+  cr-input {
+    --cr-input-error-display: none;
+  }
+</style>
+
+<h1>cr-toast</h1>
+<div class="demos">
+  <cr-input type="text" label="Toast message" value="{{message_}}"></cr-input>
+  <cr-checkbox checked="{{showDismissButton_}}">
+    Show dismiss button
+  </cr-checkbox>
+  <cr-input type="number" label="Duration (ms)" value="{{duration_}}">
+  </cr-input>
+
+  <cr-button on-click="onShowToastClick_">Show toast</cr-button>
+</div>
+
+<h1>cr-toast-manager</h1>
+<div class="demos">
+  <div>
+    One single toast manager per top-level app that allows for more dynamic
+    toast messages that can be truncated if strings are too long.
+  </div>
+
+  <cr-button on-click="onShowToastManagerClick_">
+    Show toast from toast manager
+  </cr-button>
+</div>
+
+<cr-toast id="toast" duration="[[duration_]]">
+  <div>[[message_]]</div>
+  <cr-button hidden$="[[!showDismissButton_]]" on-click="onHideToastClick_">
+    Dismiss
+  </cr-button>
+</cr-toast>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_toast/cr_toast_demo.ts b/chrome/browser/resources/webui_gallery/demos/cr_toast/cr_toast_demo.ts
new file mode 100644
index 0000000..da0a655
--- /dev/null
+++ b/chrome/browser/resources/webui_gallery/demos/cr_toast/cr_toast_demo.ts
@@ -0,0 +1,65 @@
+// 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 '//resources/cr_elements/cr_button/cr_button.js';
+import '//resources/cr_elements/cr_checkbox/cr_checkbox.js';
+import '//resources/cr_elements/cr_input/cr_input.js';
+import '//resources/cr_elements/cr_toast/cr_toast.js';
+
+import {CrToastElement} from '//resources/cr_elements/cr_toast/cr_toast.js';
+import {getToastManager} from '//resources/cr_elements/cr_toast/cr_toast_manager.js';
+import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {getTemplate} from './cr_toast_demo.html.js';
+
+interface CrToastDemoElement {
+  $: {
+    toast: CrToastElement,
+  };
+}
+
+class CrToastDemoElement extends PolymerElement {
+  static get is() {
+    return 'cr-toast-demo';
+  }
+
+  static get template() {
+    return getTemplate();
+  }
+
+  static get properties() {
+    return {
+      message_: String,
+      duration_: Number,
+      showDismissButton_: Boolean,
+    };
+  }
+
+  private duration_: number = 0;
+  private message_: string = 'Hello, world';
+  private showDismissButton_: boolean = false;
+
+  private onHideToastClick_() {
+    this.$.toast.hide();
+  }
+
+  private onShowToastManagerClick_() {
+    getToastManager().showForStringPieces([
+      {value: '\'', collapsible: false},
+      {
+        value: 'This is a really really really really long title that should ' +
+            'you an idea of some dynamic text that can be truncated.',
+        collapsible: true,
+      },
+      {value: '\' ', collapsible: false},
+      {value: 'is a message.', collapsible: false},
+    ]);
+  }
+
+  private onShowToastClick_() {
+    this.$.toast.show();
+  }
+}
+
+customElements.define(CrToastDemoElement.is, CrToastDemoElement);
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_toast/cr_toast_demo_component.html b/chrome/browser/resources/webui_gallery/demos/cr_toast/cr_toast_demo_component.html
deleted file mode 100644
index 68e03dc7..0000000
--- a/chrome/browser/resources/webui_gallery/demos/cr_toast/cr_toast_demo_component.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<link rel="stylesheet" href="../demo.css">
-<style>
-  cr-input {
-    --cr-input-error-display: none;
-  }
-</style>
-
-<h1>cr-toast</h1>
-<div class="demos">
-  <cr-input type="text" label="Toast message" value="{{message_}}"></cr-input>
-  <cr-checkbox checked="{{showDismissButton_}}">
-    Show dismiss button
-  </cr-checkbox>
-  <cr-input type="number" label="Duration (ms)" value="{{duration_}}">
-  </cr-input>
-
-  <cr-button on-click="onShowToastClick_">Show toast</cr-button>
-</div>
-
-<h1>cr-toast-manager</h1>
-<div class="demos">
-  <div>
-    One single toast manager per top-level app that allows for more dynamic
-    toast messages that can be truncated if strings are too long.
-  </div>
-
-  <cr-button on-click="onShowToastManagerClick_">
-    Show toast from toast manager
-  </cr-button>
-</div>
-
-<cr-toast id="toast" duration="[[duration_]]">
-  <div>[[message_]]</div>
-  <cr-button hidden$="[[!showDismissButton_]]" on-click="onHideToastClick_">
-    Dismiss
-  </cr-button>
-</cr-toast>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_toast/cr_toast_demo_component.ts b/chrome/browser/resources/webui_gallery/demos/cr_toast/cr_toast_demo_component.ts
deleted file mode 100644
index cd4eead..0000000
--- a/chrome/browser/resources/webui_gallery/demos/cr_toast/cr_toast_demo_component.ts
+++ /dev/null
@@ -1,65 +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 'chrome://resources/cr_elements/cr_button/cr_button.js';
-import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js';
-import 'chrome://resources/cr_elements/cr_input/cr_input.js';
-import 'chrome://resources/cr_elements/cr_toast/cr_toast.js';
-
-import {CrToastElement} from 'chrome://resources/cr_elements/cr_toast/cr_toast.js';
-import {getToastManager} from 'chrome://resources/cr_elements/cr_toast/cr_toast_manager.js';
-import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {getTemplate} from './cr_toast_demo_component.html.js';
-
-interface CrToastDemoComponent {
-  $: {
-    toast: CrToastElement,
-  };
-}
-
-class CrToastDemoComponent extends PolymerElement {
-  static get is() {
-    return 'cr-toast-demo';
-  }
-
-  static get template() {
-    return getTemplate();
-  }
-
-  static get properties() {
-    return {
-      message_: String,
-      duration_: Number,
-      showDismissButton_: Boolean,
-    };
-  }
-
-  private duration_: number = 0;
-  private message_: string = 'Hello, world';
-  private showDismissButton_: boolean = false;
-
-  private onHideToastClick_() {
-    this.$.toast.hide();
-  }
-
-  private onShowToastManagerClick_() {
-    getToastManager().showForStringPieces([
-      {value: '\'', collapsible: false},
-      {
-        value: 'This is a really really really really long title that should ' +
-            'you an idea of some dynamic text that can be truncated.',
-        collapsible: true,
-      },
-      {value: '\' ', collapsible: false},
-      {value: 'is a message.', collapsible: false},
-    ]);
-  }
-
-  private onShowToastClick_() {
-    this.$.toast.show();
-  }
-}
-
-customElements.define(CrToastDemoComponent.is, CrToastDemoComponent);
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_toast/index.html b/chrome/browser/resources/webui_gallery/demos/cr_toast/index.html
new file mode 100644
index 0000000..67a338e
--- /dev/null
+++ b/chrome/browser/resources/webui_gallery/demos/cr_toast/index.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>cr-toast demo</title>
+    <link rel="stylesheet" href="../demo.css">
+  </head>
+  <body>
+    <cr-toast-demo></cr-toast-demo>
+    <cr-toast-manager duration="5000"></cr-toast-manager>
+    <script src="//resources/cr_elements/cr_toast/cr_toast_manager.js"
+        type="module"></script>
+    <script src="cr_toast_demo.js" type="module"></script>
+  </body>
+</html>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_toggle_demo.html b/chrome/browser/resources/webui_gallery/demos/cr_toggle_demo.html
index 1c1ef6e..17380c8c 100644
--- a/chrome/browser/resources/webui_gallery/demos/cr_toggle_demo.html
+++ b/chrome/browser/resources/webui_gallery/demos/cr_toggle_demo.html
@@ -41,7 +41,7 @@
       </template>
     </dom-bind>
 
-    <script src="chrome://resources/cr_elements/cr_toggle/cr_toggle.js"
+    <script src="//resources/cr_elements/cr_toggle/cr_toggle.js"
         type="module"></script>
   </body>
 </html>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_toolbar/cr_toolbar_demo.html b/chrome/browser/resources/webui_gallery/demos/cr_toolbar/cr_toolbar_demo.html
index 6e9a2db..d95da8a 100644
--- a/chrome/browser/resources/webui_gallery/demos/cr_toolbar/cr_toolbar_demo.html
+++ b/chrome/browser/resources/webui_gallery/demos/cr_toolbar/cr_toolbar_demo.html
@@ -1,17 +1,51 @@
-<!doctype html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>cr-toolbar demo</title>
-    <link rel="stylesheet" href="../demo.css">
-    <style>
-      body {
-        padding: 0;
-      }
-    </style>
-  </head>
-  <body>
-    <cr-toolbar-demo></cr-toolbar-demo>
-    <script src="cr_toolbar_demo_component.js" type="module"></script>
-  </body>
-</html>
+<link rel="stylesheet" href="../demo.css">
+<style>
+  .content {
+    padding: 16px;
+  }
+
+  cr-input {
+    --cr-input-error-display: none;
+  }
+</style>
+<cr-toolbar
+    page-name="[[pageName_]]"
+    search-prompt="[[searchPrompt_]]"
+    clear-label="[[clearLabel_]]"
+    menu-label="[[menuLabel_]]"
+    narrow="{{narrow_}}"
+    narrow-threshold="[[narrowThreshold_]]"
+    always-show-logo="[[alwaysShowLogo_]]"
+    show-menu="[[showMenu_]]"
+    show-search="[[showSearch_]]"
+    on-cr-toolbar-menu-tap="onMenuTap_"
+    on-search-changed="onSearchChanged_">
+  <div hidden$="[[!showSlottedContent_]]">
+    Slotted right-hand content
+  </div>
+</cr-toolbar>
+
+<div class="content">
+  <h1>cr-toolbar</h1>
+  <div class="demos">
+    <cr-input label="Page name" value="{{pageName_}}"></cr-input>
+    <cr-input label="Search prompt" value="{{searchPrompt_}}"></cr-input>
+    <cr-input label="Clear label" value="{{clearLabel_}}"></cr-input>
+    <cr-input label="Menu label" value="{{menuLabel_}}"></cr-input>
+    <cr-input label="Max window width for narrow mode"
+        value="{{narrowThreshold_}}"></cr-input>
+    <cr-checkbox checked="{{alwaysShowLogo_}}">Always show logo</cr-checkbox>
+    <cr-checkbox checked="{{showMenu_}}">Show menu button</cr-checkbox>
+    <cr-checkbox checked="{{showSearch_}}">Show search input</cr-checkbox>
+    <cr-checkbox checked="{{showSlottedContent_}}">
+      Show right-hand content
+    </cr-checkbox>
+  </div>
+
+  <div class="log">
+    <div>Is narrow? [[narrow_]]</div>
+    <template is="dom-repeat" items="[[log_]]">
+      <div>[[item]]</div>
+    </template>
+  </div>
+</div>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_toolbar/cr_toolbar_demo_component.ts b/chrome/browser/resources/webui_gallery/demos/cr_toolbar/cr_toolbar_demo.ts
similarity index 73%
rename from chrome/browser/resources/webui_gallery/demos/cr_toolbar/cr_toolbar_demo_component.ts
rename to chrome/browser/resources/webui_gallery/demos/cr_toolbar/cr_toolbar_demo.ts
index d8d5448b..8182511 100644
--- a/chrome/browser/resources/webui_gallery/demos/cr_toolbar/cr_toolbar_demo_component.ts
+++ b/chrome/browser/resources/webui_gallery/demos/cr_toolbar/cr_toolbar_demo.ts
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js';
-import 'chrome://resources/cr_elements/cr_input/cr_input.js';
-import 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar.js';
+import '//resources/cr_elements/cr_checkbox/cr_checkbox.js';
+import '//resources/cr_elements/cr_input/cr_input.js';
+import '//resources/cr_elements/cr_toolbar/cr_toolbar.js';
 
-import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-import {getTemplate} from './cr_toolbar_demo_component.html.js';
+import {getTemplate} from './cr_toolbar_demo.html.js';
 
-class CrToolbarDemoComponent extends PolymerElement {
+class CrToolbarDemoElement extends PolymerElement {
   static get is() {
     return 'cr-toolbar-demo';
   }
@@ -60,4 +60,4 @@
   }
 }
 
-customElements.define(CrToolbarDemoComponent.is, CrToolbarDemoComponent);
+customElements.define(CrToolbarDemoElement.is, CrToolbarDemoElement);
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_toolbar/cr_toolbar_demo_component.html b/chrome/browser/resources/webui_gallery/demos/cr_toolbar/cr_toolbar_demo_component.html
deleted file mode 100644
index d95da8a..0000000
--- a/chrome/browser/resources/webui_gallery/demos/cr_toolbar/cr_toolbar_demo_component.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<link rel="stylesheet" href="../demo.css">
-<style>
-  .content {
-    padding: 16px;
-  }
-
-  cr-input {
-    --cr-input-error-display: none;
-  }
-</style>
-<cr-toolbar
-    page-name="[[pageName_]]"
-    search-prompt="[[searchPrompt_]]"
-    clear-label="[[clearLabel_]]"
-    menu-label="[[menuLabel_]]"
-    narrow="{{narrow_}}"
-    narrow-threshold="[[narrowThreshold_]]"
-    always-show-logo="[[alwaysShowLogo_]]"
-    show-menu="[[showMenu_]]"
-    show-search="[[showSearch_]]"
-    on-cr-toolbar-menu-tap="onMenuTap_"
-    on-search-changed="onSearchChanged_">
-  <div hidden$="[[!showSlottedContent_]]">
-    Slotted right-hand content
-  </div>
-</cr-toolbar>
-
-<div class="content">
-  <h1>cr-toolbar</h1>
-  <div class="demos">
-    <cr-input label="Page name" value="{{pageName_}}"></cr-input>
-    <cr-input label="Search prompt" value="{{searchPrompt_}}"></cr-input>
-    <cr-input label="Clear label" value="{{clearLabel_}}"></cr-input>
-    <cr-input label="Menu label" value="{{menuLabel_}}"></cr-input>
-    <cr-input label="Max window width for narrow mode"
-        value="{{narrowThreshold_}}"></cr-input>
-    <cr-checkbox checked="{{alwaysShowLogo_}}">Always show logo</cr-checkbox>
-    <cr-checkbox checked="{{showMenu_}}">Show menu button</cr-checkbox>
-    <cr-checkbox checked="{{showSearch_}}">Show search input</cr-checkbox>
-    <cr-checkbox checked="{{showSlottedContent_}}">
-      Show right-hand content
-    </cr-checkbox>
-  </div>
-
-  <div class="log">
-    <div>Is narrow? [[narrow_]]</div>
-    <template is="dom-repeat" items="[[log_]]">
-      <div>[[item]]</div>
-    </template>
-  </div>
-</div>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_toolbar/index.html b/chrome/browser/resources/webui_gallery/demos/cr_toolbar/index.html
new file mode 100644
index 0000000..0be56d5
--- /dev/null
+++ b/chrome/browser/resources/webui_gallery/demos/cr_toolbar/index.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>cr-toolbar demo</title>
+    <link rel="stylesheet" href="../demo.css">
+    <style>
+      body {
+        padding: 0;
+      }
+    </style>
+  </head>
+  <body>
+    <cr-toolbar-demo></cr-toolbar-demo>
+    <script src="cr_toolbar_demo.js" type="module"></script>
+  </body>
+</html>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_tree/cr_tree_demo.html b/chrome/browser/resources/webui_gallery/demos/cr_tree/cr_tree_demo.html
index 4063582..8a3b4fa6 100644
--- a/chrome/browser/resources/webui_gallery/demos/cr_tree/cr_tree_demo.html
+++ b/chrome/browser/resources/webui_gallery/demos/cr_tree/cr_tree_demo.html
@@ -1,12 +1,29 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>cr-tree demo</title>
-    <link rel="stylesheet" href="../demo.css">
-  </head>
-  <body>
-    <cr-tree-demo></cr-tree-demo>
-    <script src="cr_tree_demo_component.js" type="module"></script>
-  </body>
-</html>
+<link rel="stylesheet" href="../demo.css">
+<style>
+  cr-tree:not([has-children]) ~ #clearAll,
+  cr-tree:not([has-children]) ~ #collapseAll,
+  cr-tree:not([has-children]) ~ #expandAll {
+    display: none;
+  }
+
+  cr-tree[has-children] ~ #populateTree {
+    display: none;
+  }
+</style>
+
+<h1>cr-tree</h1>
+<div class="demos">
+  <cr-tree></cr-tree>
+
+  <label id="iconVisibilityContainer">
+    <input type="checkbox" id="iconVisibility" checked>
+    Show folder icons
+  </label>
+
+  <button id="expandAll">Expand All</button>
+  <button id="collapseAll">Collapse All</button>
+  <button id="addItem">Add item</button>
+  <button id="removeItem">Remove item</button>
+
+  <div id="log"></div>
+</div>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_tree/cr_tree_demo_component.ts b/chrome/browser/resources/webui_gallery/demos/cr_tree/cr_tree_demo.ts
similarity index 87%
rename from chrome/browser/resources/webui_gallery/demos/cr_tree/cr_tree_demo_component.ts
rename to chrome/browser/resources/webui_gallery/demos/cr_tree/cr_tree_demo.ts
index de611c0c..3e917ba 100644
--- a/chrome/browser/resources/webui_gallery/demos/cr_tree/cr_tree_demo_component.ts
+++ b/chrome/browser/resources/webui_gallery/demos/cr_tree/cr_tree_demo.ts
@@ -2,17 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'chrome://resources/cr_elements/cr_tree/cr_tree.js';
-import 'chrome://resources/cr_elements/cr_tree/cr_tree_item.js';
+import '//resources/cr_elements/cr_tree/cr_tree.js';
+import '//resources/cr_elements/cr_tree/cr_tree_item.js';
 
-import {CrTreeElement} from 'chrome://resources/cr_elements/cr_tree/cr_tree.js';
-import {CrTreeItemElement} from 'chrome://resources/cr_elements/cr_tree/cr_tree_item.js';
-import {assert} from 'chrome://resources/js/assert_ts.js';
-import {CustomElement} from 'chrome://resources/js/custom_element.js';
+import {CrTreeElement} from '//resources/cr_elements/cr_tree/cr_tree.js';
+import {CrTreeItemElement} from '//resources/cr_elements/cr_tree/cr_tree_item.js';
+import {assert} from '//resources/js/assert_ts.js';
+import {CustomElement} from '//resources/js/custom_element.js';
 
-import {getTemplate} from './cr_tree_demo_component.html.js';
+import {getTemplate} from './cr_tree_demo.html.js';
 
-class CrTreeDemoComponent extends CustomElement {
+class CrTreeDemoElement extends CustomElement {
   static override get template() {
     return getTemplate();
   }
@@ -147,4 +147,4 @@
   }
 }
 
-customElements.define('cr-tree-demo', CrTreeDemoComponent);
+customElements.define('cr-tree-demo', CrTreeDemoElement);
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_tree/cr_tree_demo_component.html b/chrome/browser/resources/webui_gallery/demos/cr_tree/cr_tree_demo_component.html
deleted file mode 100644
index 8a3b4fa6..0000000
--- a/chrome/browser/resources/webui_gallery/demos/cr_tree/cr_tree_demo_component.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<link rel="stylesheet" href="../demo.css">
-<style>
-  cr-tree:not([has-children]) ~ #clearAll,
-  cr-tree:not([has-children]) ~ #collapseAll,
-  cr-tree:not([has-children]) ~ #expandAll {
-    display: none;
-  }
-
-  cr-tree[has-children] ~ #populateTree {
-    display: none;
-  }
-</style>
-
-<h1>cr-tree</h1>
-<div class="demos">
-  <cr-tree></cr-tree>
-
-  <label id="iconVisibilityContainer">
-    <input type="checkbox" id="iconVisibility" checked>
-    Show folder icons
-  </label>
-
-  <button id="expandAll">Expand All</button>
-  <button id="collapseAll">Collapse All</button>
-  <button id="addItem">Add item</button>
-  <button id="removeItem">Remove item</button>
-
-  <div id="log"></div>
-</div>
diff --git a/chrome/browser/resources/webui_gallery/demos/cr_tree/index.html b/chrome/browser/resources/webui_gallery/demos/cr_tree/index.html
new file mode 100644
index 0000000..8deba0e
--- /dev/null
+++ b/chrome/browser/resources/webui_gallery/demos/cr_tree/index.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>cr-tree demo</title>
+    <link rel="stylesheet" href="../demo.css">
+  </head>
+  <body>
+    <cr-tree-demo></cr-tree-demo>
+    <script src="cr_tree_demo.js" type="module"></script>
+  </body>
+</html>
diff --git a/chrome/browser/resources/webui_gallery/demos/demo.css b/chrome/browser/resources/webui_gallery/demos/demo.css
index 0254cb1..25f49f6 100644
--- a/chrome/browser/resources/webui_gallery/demos/demo.css
+++ b/chrome/browser/resources/webui_gallery/demos/demo.css
@@ -2,7 +2,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file. */
 
-@import 'chrome://resources/css/text_defaults_md.css';
+@import '//resources/css/text_defaults_md.css';
 
 body {
   box-sizing: border-box;
diff --git a/chrome/browser/resources/webui_gallery/demos/md_select/index.html b/chrome/browser/resources/webui_gallery/demos/md_select/index.html
new file mode 100644
index 0000000..c48732bc
--- /dev/null
+++ b/chrome/browser/resources/webui_gallery/demos/md_select/index.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>md-select demo</title>
+    <link rel="stylesheet" href="../demo.css">
+  </head>
+  <body>
+    <md-select-demo></md-select-demo>
+    <script src="md_select_demo.js" type="module"></script>
+  </body>
+</html>
diff --git a/chrome/browser/resources/webui_gallery/demos/md_select/md_select_demo.html b/chrome/browser/resources/webui_gallery/demos/md_select/md_select_demo.html
index 7739e47..90a21b7c0 100644
--- a/chrome/browser/resources/webui_gallery/demos/md_select/md_select_demo.html
+++ b/chrome/browser/resources/webui_gallery/demos/md_select/md_select_demo.html
@@ -1,12 +1,30 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>md-select demo</title>
-    <link rel="stylesheet" href="../demo.css">
-  </head>
-  <body>
-    <md-select-demo></md-select-demo>
-    <script src="md_select_demo_component.js" type="module"></script>
-  </body>
-</html>
+<link rel="stylesheet" href="../demo.css">
+<style include="md-select">
+</style>
+
+<h1>Select menus</h1>
+<div class="demos">
+  <div class="row center">
+    <label id="label">Select an option</label>
+    <select id="select" class="md-select" value="[[selectedOption_]]"
+        on-change="onSelectValueChanged_"
+        aria-labelledby="label">
+      <option value="one">Option 1</option>
+      <option value="two">Option 2</option>
+      <option value="three">Option 3</option>
+      <option value="four">Option 4</option>
+      <option value="five">Option 5</option>
+    </select>
+  </div>
+
+  <div>Selected value: [[selectedOption_]]</div>
+
+  <div class="row center">
+    <label id="disabled-label">Select an option</label>
+    <select class="md-select" disabled aria-labelledby="disabled-label">
+      <option>Disabled option 1</option>
+      <option>Disabled option 2</option>
+      <option selected>Disabled option 3</option>
+    </select>
+  </div>
+</div>
diff --git a/chrome/browser/resources/webui_gallery/demos/md_select/md_select_demo.ts b/chrome/browser/resources/webui_gallery/demos/md_select/md_select_demo.ts
new file mode 100644
index 0000000..0824f63
--- /dev/null
+++ b/chrome/browser/resources/webui_gallery/demos/md_select/md_select_demo.ts
@@ -0,0 +1,39 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import '//resources/cr_elements/md_select.css.js';
+
+import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {getTemplate} from './md_select_demo.html.js';
+
+interface MdSelectDemoElement {
+  $: {
+    select: HTMLSelectElement,
+  };
+}
+
+class MdSelectDemoElement extends PolymerElement {
+  static get is() {
+    return 'md-select-demo';
+  }
+
+  static get template() {
+    return getTemplate();
+  }
+
+  static get properties() {
+    return {
+      selectedOption_: String,
+    };
+  }
+
+  private selectedOption_: string = 'two';
+
+  private onSelectValueChanged_() {
+    this.selectedOption_ = this.$.select.value;
+  }
+}
+
+customElements.define(MdSelectDemoElement.is, MdSelectDemoElement);
diff --git a/chrome/browser/resources/webui_gallery/demos/md_select/md_select_demo_component.html b/chrome/browser/resources/webui_gallery/demos/md_select/md_select_demo_component.html
deleted file mode 100644
index 90a21b7c0..0000000
--- a/chrome/browser/resources/webui_gallery/demos/md_select/md_select_demo_component.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<link rel="stylesheet" href="../demo.css">
-<style include="md-select">
-</style>
-
-<h1>Select menus</h1>
-<div class="demos">
-  <div class="row center">
-    <label id="label">Select an option</label>
-    <select id="select" class="md-select" value="[[selectedOption_]]"
-        on-change="onSelectValueChanged_"
-        aria-labelledby="label">
-      <option value="one">Option 1</option>
-      <option value="two">Option 2</option>
-      <option value="three">Option 3</option>
-      <option value="four">Option 4</option>
-      <option value="five">Option 5</option>
-    </select>
-  </div>
-
-  <div>Selected value: [[selectedOption_]]</div>
-
-  <div class="row center">
-    <label id="disabled-label">Select an option</label>
-    <select class="md-select" disabled aria-labelledby="disabled-label">
-      <option>Disabled option 1</option>
-      <option>Disabled option 2</option>
-      <option selected>Disabled option 3</option>
-    </select>
-  </div>
-</div>
diff --git a/chrome/browser/resources/webui_gallery/demos/md_select/md_select_demo_component.ts b/chrome/browser/resources/webui_gallery/demos/md_select/md_select_demo_component.ts
deleted file mode 100644
index 400e986..0000000
--- a/chrome/browser/resources/webui_gallery/demos/md_select/md_select_demo_component.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'chrome://resources/cr_elements/md_select.css.js';
-
-import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {getTemplate} from './md_select_demo_component.html.js';
-
-interface MdSelectDemoComponent {
-  $: {
-    select: HTMLSelectElement,
-  };
-}
-
-class MdSelectDemoComponent extends PolymerElement {
-  static get is() {
-    return 'md-select-demo';
-  }
-
-  static get template() {
-    return getTemplate();
-  }
-
-  static get properties() {
-    return {
-      selectedOption_: String,
-    };
-  }
-
-  private selectedOption_: string = 'two';
-
-  private onSelectValueChanged_() {
-    this.selectedOption_ = this.$.select.value;
-  }
-}
-
-customElements.define(MdSelectDemoComponent.is, MdSelectDemoComponent);
diff --git a/chrome/browser/resources/webui_gallery/demos/nav_menu/nav_menu.ts b/chrome/browser/resources/webui_gallery/demos/nav_menu/nav_menu.ts
index 6b4a626..3acdd16e 100644
--- a/chrome/browser/resources/webui_gallery/demos/nav_menu/nav_menu.ts
+++ b/chrome/browser/resources/webui_gallery/demos/nav_menu/nav_menu.ts
@@ -13,13 +13,13 @@
 
 import {getTemplate} from './nav_menu.html.js';
 
-interface NavMenuComponent {
+interface NavMenuElement {
   $: {
     selector: IronSelectorElement,
   };
 }
 
-class NavMenuComponent extends PolymerElement {
+class NavMenuElement extends PolymerElement {
   static get is() {
     return 'nav-menu';
   }
@@ -77,4 +77,4 @@
   }
 }
 
-customElements.define(NavMenuComponent.is, NavMenuComponent);
+customElements.define(NavMenuElement.is, NavMenuElement);
diff --git a/chrome/browser/resources/webui_gallery/demos/nav_menu/nav_menu_demo.ts b/chrome/browser/resources/webui_gallery/demos/nav_menu/nav_menu_demo.ts
index 4598332..5d66cabf 100644
--- a/chrome/browser/resources/webui_gallery/demos/nav_menu/nav_menu_demo.ts
+++ b/chrome/browser/resources/webui_gallery/demos/nav_menu/nav_menu_demo.ts
@@ -13,13 +13,13 @@
 
 import {getTemplate} from './nav_menu_demo.html.js';
 
-interface NavMenuDemoComponent {
+interface NavMenuDemoElement {
   $: {
     drawer: CrDrawerElement,
   };
 }
 
-class NavMenuDemoComponent extends PolymerElement {
+class NavMenuDemoElement extends PolymerElement {
   static get is() {
     return 'nav-menu-demo';
   }
@@ -68,4 +68,4 @@
   }
 }
 
-customElements.define(NavMenuDemoComponent.is, NavMenuDemoComponent);
+customElements.define(NavMenuDemoElement.is, NavMenuDemoElement);
diff --git a/chrome/browser/resources/webui_gallery/demos/progress_indicator_nonpolymer_demo.html b/chrome/browser/resources/webui_gallery/demos/progress_indicator_nonpolymer_demo.html
index a662fe7..6ecf96a 100644
--- a/chrome/browser/resources/webui_gallery/demos/progress_indicator_nonpolymer_demo.html
+++ b/chrome/browser/resources/webui_gallery/demos/progress_indicator_nonpolymer_demo.html
@@ -3,8 +3,8 @@
   <head>
     <meta charset="utf-8">
     <title>Progress indicators demo</title>
-    <link rel="stylesheet" href="chrome://resources/css/spinner.css">
-    <link rel="stylesheet" href="chrome://resources/css/throbber.css">
+    <link rel="stylesheet" href="//resources/css/spinner.css">
+    <link rel="stylesheet" href="//resources/css/throbber.css">
     <link rel="stylesheet" href="demo.css">
   </head>
   <body>
diff --git a/chrome/browser/resources/webui_gallery/demos/progress_indicator_polymer_demo.html b/chrome/browser/resources/webui_gallery/demos/progress_indicator_polymer_demo.html
index 1de9ef2..2b4134a0 100644
--- a/chrome/browser/resources/webui_gallery/demos/progress_indicator_polymer_demo.html
+++ b/chrome/browser/resources/webui_gallery/demos/progress_indicator_polymer_demo.html
@@ -37,13 +37,13 @@
       <paper-spinner-lite active></paper-spinner-lite>
     </div>
 
-    <script src="chrome://resources/cr_elements/cr_shared_vars.css.js"
+    <script src="//resources/cr_elements/cr_shared_vars.css.js"
         type="module"></script>
     <script
-        src="chrome://resources/polymer/v3_0/paper-progress/paper-progress.js"
+        src="//resources/polymer/v3_0/paper-progress/paper-progress.js"
         type="module"></script>
     <script
-        src="chrome://resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js"
+        src="//resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js"
         type="module"></script>
   </body>
 </html>
diff --git a/chrome/browser/resources/webui_gallery/demos/scroll_view/index.html b/chrome/browser/resources/webui_gallery/demos/scroll_view/index.html
new file mode 100644
index 0000000..78163044
--- /dev/null
+++ b/chrome/browser/resources/webui_gallery/demos/scroll_view/index.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>Scroll view demo</title>
+    <link rel="stylesheet" href="../demo.css">
+  </head>
+  <body>
+    <scroll-view-demo></scroll-view-demo>
+    <script src="scroll_view_demo.js" type="module"></script>
+  </body>
+</html>
diff --git a/chrome/browser/resources/webui_gallery/demos/scroll_view/scroll_view_demo.html b/chrome/browser/resources/webui_gallery/demos/scroll_view/scroll_view_demo.html
index e08dab0..e7332b5 100644
--- a/chrome/browser/resources/webui_gallery/demos/scroll_view/scroll_view_demo.html
+++ b/chrome/browser/resources/webui_gallery/demos/scroll_view/scroll_view_demo.html
@@ -1,12 +1,99 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Scroll view demo</title>
-    <link rel="stylesheet" href="../demo.css">
-  </head>
-  <body>
-    <scroll-view-demo></scroll-view-demo>
-    <script src="scroll_view_demo_component.js" type="module"></script>
-  </body>
-</html>
+<link rel="stylesheet" href="../demo.css">
+<style include="cr-shared-style">
+  #layout {
+    display: flex;
+    flex-direction: column;
+    width: 100%;
+  }
+
+  /* Parent of #container for CrContainerShadowMixin needs to be flex column. */
+  #layout {
+    display: flex;
+    flex-direction: column;
+  }
+
+  #container {
+    height: 500px;
+    overflow: auto;
+    position: relative;
+    width: 100%;
+  }
+
+  #mockContent {
+    background: linear-gradient(180deg, white, black);
+    height: 200%;
+    width: 100%;
+  }
+
+  #ironListScrollView {
+    max-height: 300px;
+    width: 100%;
+  }
+
+  .item {
+    padding: 16px;
+    text-align: center;
+    width: 100%;
+  }
+
+  #canScrollLog,
+  #isScrolledLog,
+  #scrolledToBottomLog {
+    display: none;
+  }
+
+  .can-scroll ~ #canScrollLog {
+    display: block;
+  }
+
+  .is-scrolled ~ #isScrolledLog {
+    display: block;
+  }
+
+  .scrolled-to-bottom ~ #scrolledToBottomLog {
+    display: block;
+  }
+
+  #sliderContainer {
+    align-items: center;
+    display: flex;
+    gap: 12px;
+  }
+
+  #itemsLengthSlider {
+    width: 200px;
+  }
+</style>
+
+<h1>Scroll view with shadows indicating scroll</h1>
+<div class="demos">
+  <div id="layout">
+    <div id="container" show-bottom-shadow>
+      <div id="mockContent"></div>
+    </div>
+  </div>
+</div>
+
+<h1>Scroll view with &lt;iron-list&gt; and dynamic height</h1>
+<div class="demos">
+  <div id="sliderContainer">
+    <label id="sliderLabel">Number of items in iron-list</label>
+    <cr-slider id="itemsLengthSlider" min="0" max="30" value="[[items_.length]]"
+        aria-labelledby="sliderLabel"
+        on-cr-slider-value-changed="onItemsLengthChanged_">
+    </cr-slider>
+    [[items_.length]]
+  </div>
+
+  <div id="ironListScrollView" scrollable>
+    <iron-list items="[[items_]]" scroll-target="ironListScrollView">
+      <template>
+        <div class="item" tabindex="0">Focusable item</div>
+      </template>
+    </iron-list>
+  </div>
+
+  <div id="canScrollLog">can scroll</div>
+  <div id="isScrolledLog">is scrolled</div>
+  <div id="scrolledToBottomLog">scrolled to bottom</div>
+</div>
diff --git a/chrome/browser/resources/webui_gallery/demos/scroll_view/scroll_view_demo.ts b/chrome/browser/resources/webui_gallery/demos/scroll_view/scroll_view_demo.ts
new file mode 100644
index 0000000..4698a64
--- /dev/null
+++ b/chrome/browser/resources/webui_gallery/demos/scroll_view/scroll_view_demo.ts
@@ -0,0 +1,62 @@
+// 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 '//resources/cr_elements/cr_shared_style.css.js';
+import '//resources/cr_elements/cr_shared_vars.css.js';
+import '//resources/polymer/v3_0/iron-list/iron-list.js';
+import '//resources/cr_elements/cr_slider/cr_slider.js';
+
+import {CrContainerShadowMixin} from '//resources/cr_elements/cr_container_shadow_mixin.js';
+import {CrScrollableMixin} from '//resources/cr_elements/cr_scrollable_mixin.js';
+import {CrSliderElement} from '//resources/cr_elements/cr_slider/cr_slider.js';
+import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {getTemplate} from './scroll_view_demo.html.js';
+
+interface ScrollViewDemoElement {
+  $: {
+    itemsLengthSlider: CrSliderElement,
+  };
+}
+
+const ScrollViewDemoElementBase =
+    CrContainerShadowMixin(CrScrollableMixin(PolymerElement));
+
+class ScrollViewDemoElement extends ScrollViewDemoElementBase {
+  static get is() {
+    return 'scroll-view-demo';
+  }
+
+  static get template() {
+    return getTemplate();
+  }
+
+  static get properties() {
+    return {
+      items_: {
+        type: Array,
+        value: () => [0, 1, 2, 3],
+      },
+    };
+  }
+
+  private items_: number[];
+
+  override ready() {
+    super.ready();
+    this.updateScrollableContents();
+  }
+
+  private onItemsLengthChanged_() {
+    const length = this.$.itemsLengthSlider.value;
+    const items: number[] = [];
+    for (let i = 0; i < length; i++) {
+      items.push(i);
+    }
+    this.items_ = items;
+    this.updateScrollableContents();
+  }
+}
+
+customElements.define(ScrollViewDemoElement.is, ScrollViewDemoElement);
diff --git a/chrome/browser/resources/webui_gallery/demos/scroll_view/scroll_view_demo_component.html b/chrome/browser/resources/webui_gallery/demos/scroll_view/scroll_view_demo_component.html
deleted file mode 100644
index e7332b5..0000000
--- a/chrome/browser/resources/webui_gallery/demos/scroll_view/scroll_view_demo_component.html
+++ /dev/null
@@ -1,99 +0,0 @@
-<link rel="stylesheet" href="../demo.css">
-<style include="cr-shared-style">
-  #layout {
-    display: flex;
-    flex-direction: column;
-    width: 100%;
-  }
-
-  /* Parent of #container for CrContainerShadowMixin needs to be flex column. */
-  #layout {
-    display: flex;
-    flex-direction: column;
-  }
-
-  #container {
-    height: 500px;
-    overflow: auto;
-    position: relative;
-    width: 100%;
-  }
-
-  #mockContent {
-    background: linear-gradient(180deg, white, black);
-    height: 200%;
-    width: 100%;
-  }
-
-  #ironListScrollView {
-    max-height: 300px;
-    width: 100%;
-  }
-
-  .item {
-    padding: 16px;
-    text-align: center;
-    width: 100%;
-  }
-
-  #canScrollLog,
-  #isScrolledLog,
-  #scrolledToBottomLog {
-    display: none;
-  }
-
-  .can-scroll ~ #canScrollLog {
-    display: block;
-  }
-
-  .is-scrolled ~ #isScrolledLog {
-    display: block;
-  }
-
-  .scrolled-to-bottom ~ #scrolledToBottomLog {
-    display: block;
-  }
-
-  #sliderContainer {
-    align-items: center;
-    display: flex;
-    gap: 12px;
-  }
-
-  #itemsLengthSlider {
-    width: 200px;
-  }
-</style>
-
-<h1>Scroll view with shadows indicating scroll</h1>
-<div class="demos">
-  <div id="layout">
-    <div id="container" show-bottom-shadow>
-      <div id="mockContent"></div>
-    </div>
-  </div>
-</div>
-
-<h1>Scroll view with &lt;iron-list&gt; and dynamic height</h1>
-<div class="demos">
-  <div id="sliderContainer">
-    <label id="sliderLabel">Number of items in iron-list</label>
-    <cr-slider id="itemsLengthSlider" min="0" max="30" value="[[items_.length]]"
-        aria-labelledby="sliderLabel"
-        on-cr-slider-value-changed="onItemsLengthChanged_">
-    </cr-slider>
-    [[items_.length]]
-  </div>
-
-  <div id="ironListScrollView" scrollable>
-    <iron-list items="[[items_]]" scroll-target="ironListScrollView">
-      <template>
-        <div class="item" tabindex="0">Focusable item</div>
-      </template>
-    </iron-list>
-  </div>
-
-  <div id="canScrollLog">can scroll</div>
-  <div id="isScrolledLog">is scrolled</div>
-  <div id="scrolledToBottomLog">scrolled to bottom</div>
-</div>
diff --git a/chrome/browser/resources/webui_gallery/demos/scroll_view/scroll_view_demo_component.ts b/chrome/browser/resources/webui_gallery/demos/scroll_view/scroll_view_demo_component.ts
deleted file mode 100644
index 4471eb5..0000000
--- a/chrome/browser/resources/webui_gallery/demos/scroll_view/scroll_view_demo_component.ts
+++ /dev/null
@@ -1,62 +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 'chrome://resources/cr_elements/cr_shared_style.css.js';
-import 'chrome://resources/cr_elements/cr_shared_vars.css.js';
-import 'chrome://resources/polymer/v3_0/iron-list/iron-list.js';
-import 'chrome://resources/cr_elements/cr_slider/cr_slider.js';
-
-import {CrContainerShadowMixin} from 'chrome://resources/cr_elements/cr_container_shadow_mixin.js';
-import {CrScrollableMixin} from 'chrome://resources/cr_elements/cr_scrollable_mixin.js';
-import {CrSliderElement} from 'chrome://resources/cr_elements/cr_slider/cr_slider.js';
-import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {getTemplate} from './scroll_view_demo_component.html.js';
-
-interface ScrollViewDemoComponent {
-  $: {
-    itemsLengthSlider: CrSliderElement,
-  };
-}
-
-const ScrollViewDemoComponentBase =
-    CrContainerShadowMixin(CrScrollableMixin(PolymerElement));
-
-class ScrollViewDemoComponent extends ScrollViewDemoComponentBase {
-  static get is() {
-    return 'scroll-view-demo';
-  }
-
-  static get template() {
-    return getTemplate();
-  }
-
-  static get properties() {
-    return {
-      items_: {
-        type: Array,
-        value: () => [0, 1, 2, 3],
-      },
-    };
-  }
-
-  private items_: number[];
-
-  override ready() {
-    super.ready();
-    this.updateScrollableContents();
-  }
-
-  private onItemsLengthChanged_() {
-    const length = this.$.itemsLengthSlider.value;
-    const items: number[] = [];
-    for (let i = 0; i < length; i++) {
-      items.push(i);
-    }
-    this.items_ = items;
-    this.updateScrollableContents();
-  }
-}
-
-customElements.define(ScrollViewDemoComponent.is, ScrollViewDemoComponent);
diff --git a/chrome/browser/resources/webui_gallery/webui_gallery.gni b/chrome/browser/resources/webui_gallery/webui_gallery.gni
index 9ff0b1ae..d2e0701 100644
--- a/chrome/browser/resources/webui_gallery/webui_gallery.gni
+++ b/chrome/browser/resources/webui_gallery/webui_gallery.gni
@@ -5,25 +5,25 @@
 # Files holding a Polymer element definition AND have an equivalent .html file.
 web_component_files = [
   "app.ts",
-  "demos/card/card_demo_component.ts",
-  "demos/cr_a11y_announcer_demo_component.ts",
-  "demos/cr_action_menu_demo_component.ts",
-  "demos/cr_dialog_demo_component.ts",
-  "demos/cr_icons/cr_icons_demo_component.ts",
-  "demos/cr_input/cr_input_demo_component.ts",
-  "demos/cr_slider/cr_slider_demo_component.ts",
-  "demos/cr_tabs/cr_tabs_demo_component.ts",
-  "demos/cr_toast/cr_toast_demo_component.ts",
-  "demos/cr_toolbar/cr_toolbar_demo_component.ts",
-  "demos/md_select/md_select_demo_component.ts",
-  "demos/nav_menu/nav_menu.ts",
+  "demos/card/card_demo.ts",
+  "demos/cr_a11y_announcer/cr_a11y_announcer_demo.ts",
+  "demos/cr_action_menu/cr_action_menu_demo.ts",
+  "demos/cr_dialog/cr_dialog_demo.ts",
+  "demos/cr_icons/cr_icons_demo.ts",
+  "demos/cr_input/cr_input_demo.ts",
+  "demos/cr_slider/cr_slider_demo.ts",
+  "demos/cr_tabs/cr_tabs_demo.ts",
+  "demos/cr_toast/cr_toast_demo.ts",
+  "demos/cr_toolbar/cr_toolbar_demo.ts",
+  "demos/md_select/md_select_demo.ts",
   "demos/nav_menu/nav_menu_demo.ts",
-  "demos/scroll_view/scroll_view_demo_component.ts",
+  "demos/nav_menu/nav_menu.ts",
+  "demos/scroll_view/scroll_view_demo.ts",
 ]
 
 web_component_files_native = [
-  "demos/cr_tab_box/cr_tab_box_demo_component.ts",
-  "demos/cr_tree/cr_tree_demo_component.ts",
+  "demos/cr_tab_box/cr_tab_box_demo.ts",
+  "demos/cr_tree/cr_tree_demo.ts",
 ]
 
 # Files that are passed as input to html_to_wrapper().
diff --git a/chrome/browser/search_engines/template_url_service_unittest.cc b/chrome/browser/search_engines/template_url_service_unittest.cc
index 17fea08..8db51711 100644
--- a/chrome/browser/search_engines/template_url_service_unittest.cc
+++ b/chrome/browser/search_engines/template_url_service_unittest.cc
@@ -2302,11 +2302,18 @@
       std::make_unique<TemplateURL>(*GenerateDummyTemplateURLData("keyword")));
   DCHECK(search_engine);
 
+  // Before we activate or modify the search engine, it can be replaced by an
+  // autogenerated keyword.
+  ASSERT_TRUE(model()->CanAddAutogeneratedKeyword(u"keyword", GURL()));
+
   base::HistogramTester histogram_tester;
   model()->SetIsActiveTemplateURL(search_engine, true);
   EXPECT_EQ(search_engine->is_active(), TemplateURLData::ActiveStatus::kTrue);
   histogram_tester.ExpectTotalCount(
       "Omnibox.KeywordModeUsageByEngineType.Activated", 1);
+  // Check that we're no longer able to overwrite the keyword once it's been
+  // activated.
+  ASSERT_FALSE(model()->CanAddAutogeneratedKeyword(u"keyword", GURL()));
 
   model()->SetIsActiveTemplateURL(search_engine, false);
   EXPECT_EQ(search_engine->is_active(), TemplateURLData::ActiveStatus::kFalse);
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index cb20a4f..4992c43 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2641,6 +2641,32 @@
       "webui/ash/emoji/emoji_page_handler.h",
       "webui/ash/emoji/emoji_ui.cc",
       "webui/ash/emoji/emoji_ui.h",
+      "webui/ash/in_session_password_change/base_lock_dialog.cc",
+      "webui/ash/in_session_password_change/base_lock_dialog.h",
+      "webui/ash/in_session_password_change/confirm_password_change_handler.cc",
+      "webui/ash/in_session_password_change/confirm_password_change_handler.h",
+      "webui/ash/in_session_password_change/lock_screen_captive_portal_dialog.cc",
+      "webui/ash/in_session_password_change/lock_screen_captive_portal_dialog.h",
+      "webui/ash/in_session_password_change/lock_screen_network_dialog.cc",
+      "webui/ash/in_session_password_change/lock_screen_network_dialog.h",
+      "webui/ash/in_session_password_change/lock_screen_network_handler.cc",
+      "webui/ash/in_session_password_change/lock_screen_network_handler.h",
+      "webui/ash/in_session_password_change/lock_screen_network_ui.cc",
+      "webui/ash/in_session_password_change/lock_screen_network_ui.h",
+      "webui/ash/in_session_password_change/lock_screen_reauth_dialogs.cc",
+      "webui/ash/in_session_password_change/lock_screen_reauth_dialogs.h",
+      "webui/ash/in_session_password_change/lock_screen_reauth_handler.cc",
+      "webui/ash/in_session_password_change/lock_screen_reauth_handler.h",
+      "webui/ash/in_session_password_change/lock_screen_start_reauth_ui.cc",
+      "webui/ash/in_session_password_change/lock_screen_start_reauth_ui.h",
+      "webui/ash/in_session_password_change/password_change_dialogs.cc",
+      "webui/ash/in_session_password_change/password_change_dialogs.h",
+      "webui/ash/in_session_password_change/password_change_handler.cc",
+      "webui/ash/in_session_password_change/password_change_handler.h",
+      "webui/ash/in_session_password_change/password_change_ui.cc",
+      "webui/ash/in_session_password_change/password_change_ui.h",
+      "webui/ash/in_session_password_change/urgent_password_expiry_notification_handler.cc",
+      "webui/ash/in_session_password_change/urgent_password_expiry_notification_handler.h",
       "webui/chromeos/assistant_optin/assistant_optin_ui.cc",
       "webui/chromeos/assistant_optin/assistant_optin_ui.h",
       "webui/chromeos/assistant_optin/assistant_optin_utils.cc",
@@ -2673,32 +2699,6 @@
       "webui/chromeos/human_presence_internals_ui.h",
       "webui/chromeos/image_source.cc",
       "webui/chromeos/image_source.h",
-      "webui/chromeos/in_session_password_change/base_lock_dialog.cc",
-      "webui/chromeos/in_session_password_change/base_lock_dialog.h",
-      "webui/chromeos/in_session_password_change/confirm_password_change_handler.cc",
-      "webui/chromeos/in_session_password_change/confirm_password_change_handler.h",
-      "webui/chromeos/in_session_password_change/lock_screen_captive_portal_dialog.cc",
-      "webui/chromeos/in_session_password_change/lock_screen_captive_portal_dialog.h",
-      "webui/chromeos/in_session_password_change/lock_screen_network_dialog.cc",
-      "webui/chromeos/in_session_password_change/lock_screen_network_dialog.h",
-      "webui/chromeos/in_session_password_change/lock_screen_network_handler.cc",
-      "webui/chromeos/in_session_password_change/lock_screen_network_handler.h",
-      "webui/chromeos/in_session_password_change/lock_screen_network_ui.cc",
-      "webui/chromeos/in_session_password_change/lock_screen_network_ui.h",
-      "webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.cc",
-      "webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.h",
-      "webui/chromeos/in_session_password_change/lock_screen_reauth_handler.cc",
-      "webui/chromeos/in_session_password_change/lock_screen_reauth_handler.h",
-      "webui/chromeos/in_session_password_change/lock_screen_start_reauth_ui.cc",
-      "webui/chromeos/in_session_password_change/lock_screen_start_reauth_ui.h",
-      "webui/chromeos/in_session_password_change/password_change_dialogs.cc",
-      "webui/chromeos/in_session_password_change/password_change_dialogs.h",
-      "webui/chromeos/in_session_password_change/password_change_handler.cc",
-      "webui/chromeos/in_session_password_change/password_change_handler.h",
-      "webui/chromeos/in_session_password_change/password_change_ui.cc",
-      "webui/chromeos/in_session_password_change/password_change_ui.h",
-      "webui/chromeos/in_session_password_change/urgent_password_expiry_notification_handler.cc",
-      "webui/chromeos/in_session_password_change/urgent_password_expiry_notification_handler.h",
       "webui/chromeos/internet_config_dialog.cc",
       "webui/chromeos/internet_config_dialog.h",
       "webui/chromeos/internet_detail_dialog.cc",
@@ -3123,7 +3123,6 @@
       "//ash/services/multidevice_setup/public/cpp:android_sms_app_helper_delegate",
       "//ash/services/multidevice_setup/public/cpp:prefs",
       "//ash/services/multidevice_setup/public/cpp:url_provider",
-      "//ash/services/recording/public/mojom",
       "//ash/shortcut_viewer",
       "//ash/shortcut_viewer/strings:strings_grit",
       "//ash/webui/camera_app_ui",
@@ -3254,6 +3253,7 @@
       "//chromeos/ash/services/bluetooth_config/public/mojom",
       "//chromeos/ash/services/cellular_setup",
       "//chromeos/ash/services/cellular_setup/public/mojom",
+      "//chromeos/ash/services/recording/public/mojom",
       "//chromeos/components/onc",
       "//chromeos/components/quick_answers",
       "//chromeos/components/quick_answers/public/cpp:cpp",
diff --git a/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.cc b/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.cc
index dd249f2d..1a4fd262 100644
--- a/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.cc
+++ b/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.cc
@@ -6,7 +6,6 @@
 
 #include <memory>
 
-#include "ash/services/recording/public/mojom/recording_service.mojom.h"
 #include "base/bind.h"
 #include "base/check.h"
 #include "base/files/file_path.h"
@@ -28,6 +27,7 @@
 #include "chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h"
 #include "chrome/browser/web_applications/web_app_id_constants.h"
 #include "chrome/common/pref_names.h"
+#include "chromeos/ash/services/recording/public/mojom/recording_service.mojom.h"
 #include "chromeos/login/login_state/login_state.h"
 #include "components/drive/file_errors.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/ui/ash/login_screen_client_impl.cc b/chrome/browser/ui/ash/login_screen_client_impl.cc
index 2a10ec4..20d9131 100644
--- a/chrome/browser/ui/ash/login_screen_client_impl.cc
+++ b/chrome/browser/ui/ash/login_screen_client_impl.cc
@@ -31,7 +31,7 @@
 #include "chrome/browser/profiles/profile_metrics.h"
 #include "chrome/browser/ui/ash/wallpaper_controller_client_impl.h"
 #include "chrome/browser/ui/settings_window_manager_chromeos.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_reauth_dialogs.h"
 #include "chrome/browser/ui/webui/chromeos/login/l10n_util.h"
 #include "chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom.h"
 #include "chrome/common/webui_url_constants.h"
diff --git a/chrome/browser/ui/ash/projector/pending_screencast_manager_browsertest.cc b/chrome/browser/ui/ash/projector/pending_screencast_manager_browsertest.cc
index a19699e..8aa2c04 100644
--- a/chrome/browser/ui/ash/projector/pending_screencast_manager_browsertest.cc
+++ b/chrome/browser/ui/ash/projector/pending_screencast_manager_browsertest.cc
@@ -274,7 +274,7 @@
     CreateFileInDriveFsFolder(kDefaultMetadataFilePath, file_content);
     GetFakeDriveFs()->SetMetadata(base::FilePath(kDefaultMetadataFilePath),
                                   "text/plain", kTestMetadataFile, false, false,
-                                  {}, {}, "abc123",
+                                  false, {}, {}, "abc123",
                                   /*alternate_url=*/
                                   "https://drive.google.com/open?id=fileId");
 
@@ -773,7 +773,7 @@
   CreateFileInDriveFsFolder(kDefaultMetadataFilePath, kProjectorFileContent);
   GetFakeDriveFs()->SetMetadata(
       base::FilePath(kDefaultMetadataFilePath), "text/plain", kTestMetadataFile,
-      false, false, {}, {}, "abc123",
+      false, false, false, {}, {}, "abc123",
       /*alternate_url=*/"https://drive.google.com/open?id=fileId");
 
   // Sets get file id callback:
@@ -815,7 +815,7 @@
   // not fully populated.
   GetFakeDriveFs()->SetMetadata(base::FilePath(kDefaultMetadataFilePath),
                                 "text/plain", kTestMetadataFile, false, false,
-                                {}, {}, "abc123",
+                                false, {}, {}, "abc123",
                                 /*alternate_url=*/std::string());
 
   TestGetFileIdFailed();
@@ -827,7 +827,7 @@
   // Sets incorrect alternate url in metadata.
   GetFakeDriveFs()->SetMetadata(base::FilePath(kDefaultMetadataFilePath),
                                 "text/plain", kTestMetadataFile, false, false,
-                                {}, {}, "abc123",
+                                false, {}, {}, "abc123",
                                 /*alternate_url=*/"alternate_url");
 
   TestGetFileIdFailed();
diff --git a/chrome/browser/ui/ash/projector/screencast_manager_browsertest.cc b/chrome/browser/ui/ash/projector/screencast_manager_browsertest.cc
index 9d5203c..a184e148 100644
--- a/chrome/browser/ui/ash/projector/screencast_manager_browsertest.cc
+++ b/chrome/browser/ui/ash/projector/screencast_manager_browsertest.cc
@@ -124,8 +124,8 @@
       EXPECT_TRUE(base::WriteFile(absolute_path, kTestFileContents));
 
     const base::FilePath& relative_path = GetTestFile(title, /*relative=*/true);
-    fake->SetMetadata(relative_path, content_type, title, false, shared_with_me,
-                      {}, {}, file_id, "");
+    fake->SetMetadata(relative_path, content_type, title, false, false,
+                      shared_with_me, {}, {}, file_id, "");
   }
 
   // Copies a file from //media/test/data with `original_name` to default test
diff --git a/chrome/browser/ui/bookmarks/bookmark_utils_desktop.cc b/chrome/browser/ui/bookmarks/bookmark_utils_desktop.cc
index da69043..e9c96c94 100644
--- a/chrome/browser/ui/bookmarks/bookmark_utils_desktop.cc
+++ b/chrome/browser/ui/bookmarks/bookmark_utils_desktop.cc
@@ -356,17 +356,17 @@
   if (!saved_group)
     return;
 
-  if (saved_group->tab_group_id().has_value()) {
+  if (saved_group->local_group_id().has_value()) {
     TabStripModel* model_for_activation =
         service->listener()->GetTabStripModelWithTabGroupId(
-            saved_group->tab_group_id().value());
+            saved_group->local_group_id().value());
 
     // Only activate the tab group's first tab if it exists in any browser's
     // tabstrip model.
     if (model_for_activation) {
       absl::optional<int> first_tab =
           model_for_activation->group_model()
-              ->GetTabGroup(saved_group->tab_group_id().value())
+              ->GetTabGroup(saved_group->local_group_id().value())
               ->GetFirstTab();
       DCHECK(first_tab.has_value());
       model_for_activation->ActivateTabAt(first_tab.value());
@@ -421,7 +421,7 @@
 
   absl::optional<int> first_tab =
       model_for_creation->group_model()
-          ->GetTabGroup(saved_group->tab_group_id().value())
+          ->GetTabGroup(saved_group->local_group_id().value())
           ->GetFirstTab();
   DCHECK(first_tab.has_value());
   model_for_creation->ActivateTabAt(first_tab.value());
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
index 8ea7c24..1438019e 100644
--- a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
+++ b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
@@ -430,13 +430,14 @@
     controller_->GetWebContents()->Focus();
 }
 
-void ChromeOmniboxClient::OnSelectedMatchChanged(
+void ChromeOmniboxClient::OnNavigationLikely(
     size_t index,
-    const AutocompleteMatch& match) {
+    const AutocompleteMatch& match,
+    omnibox::mojom::NavigationPredictor navigation_predictor) {
   if (SearchPrefetchService* search_prefetch_service =
           SearchPrefetchServiceFactory::GetForProfile(profile_)) {
-    search_prefetch_service->MaybePrefetchLikelyMatch(
-        index, match, controller_->GetWebContents());
+    search_prefetch_service->OnNavigationLikely(
+        index, match, navigation_predictor, controller_->GetWebContents());
   }
 }
 
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_client.h b/chrome/browser/ui/omnibox/chrome_omnibox_client.h
index 915589b..ea6329b 100644
--- a/chrome/browser/ui/omnibox/chrome_omnibox_client.h
+++ b/chrome/browser/ui/omnibox/chrome_omnibox_client.h
@@ -15,6 +15,7 @@
 #include "chrome/browser/bitmap_fetcher/bitmap_fetcher_service.h"
 #include "chrome/common/search/instant_types.h"
 #include "components/omnibox/browser/favicon_cache.h"
+#include "components/omnibox/browser/omnibox.mojom-shared.h"
 #include "components/omnibox/browser/omnibox_client.h"
 
 class ChromeOmniboxEditController;
@@ -85,8 +86,10 @@
   void DiscardNonCommittedNavigations() override;
   void OpenUpdateChromeDialog() override;
   void FocusWebContents() override;
-  void OnSelectedMatchChanged(size_t index,
-                              const AutocompleteMatch& match) override;
+  void OnNavigationLikely(
+      size_t index,
+      const AutocompleteMatch& match,
+      omnibox::mojom::NavigationPredictor navigation_predictor) override;
 
   // Update shortcuts when a navigation succeeds.
   static void OnSuccessfulNavigation(Profile* profile,
diff --git a/chrome/browser/ui/omnibox/omnibox_pedal_implementations_unittest.cc b/chrome/browser/ui/omnibox/omnibox_pedal_implementations_unittest.cc
index 2551639e..9d4331c5 100644
--- a/chrome/browser/ui/omnibox/omnibox_pedal_implementations_unittest.cc
+++ b/chrome/browser/ui/omnibox/omnibox_pedal_implementations_unittest.cc
@@ -70,12 +70,8 @@
   // prevent clashes between concepts for different Pedals.
   void TestLiteralConceptExpressions() {
     const std::vector<std::vector<const char*>> literal_concept_expressions = {
-        // clang-format off
-        // Note: The lists below are auto-generated from raw synonym group data.
-
         // ID#1
         {
-            // Generated suggestions:
             "browser cache clear",
             "browser cache delete",
             "browser cache erase",
@@ -860,7 +856,6 @@
 
         // ID#2
         {
-            // Generated suggestions:
             "browser change password",
             "browser change passwords",
             "browser edit password",
@@ -1199,7 +1194,6 @@
 
         // ID#3
         {
-            // Generated suggestions:
             "browser card info change",
             "browser card info edit",
             "browser card info manage",
@@ -2204,7 +2198,6 @@
 
         // ID#4
         {
-            // Generated suggestions:
             "browser create incognito",
             "browser create incognito mode",
             "browser create incognito tab",
@@ -3098,7 +3091,6 @@
 
         // ID#5
         {
-            // Generated suggestions:
             "browser change language page",
             "browser change language this",
             "browser change language this page",
@@ -3303,36 +3295,22 @@
 
         // ID#6
         {
-            // Generated suggestions:
-            "browser install",
-            "browser update",
-            "browser updates",
-            "browser upgrade",
-            "chrome install",
-            "chrome update",
-            "chrome updates",
-            "chrome upgrade",
-            "google chrome install",
-            "google chrome update",
-            "google chrome updates",
-            "google chrome upgrade",
-            "install browser",
-            "install chrome",
-            "install google chrome",
-            "update browser",
-            "update chrome",
-            "update google chrome",
-            "updates browser",
-            "updates chrome",
-            "updates google chrome",
-            "upgrade browser",
-            "upgrade chrome",
-            "upgrade google chrome",
+            "browser install",       "browser update",
+            "browser updates",       "browser upgrade",
+            "chrome install",        "chrome update",
+            "chrome updates",        "chrome upgrade",
+            "google chrome install", "google chrome update",
+            "google chrome updates", "google chrome upgrade",
+            "install browser",       "install chrome",
+            "install google chrome", "update browser",
+            "update chrome",         "update google chrome",
+            "updates browser",       "updates chrome",
+            "updates google chrome", "upgrade browser",
+            "upgrade chrome",        "upgrade google chrome",
         },
 
         // ID#7
         {
-            // Generated suggestions:
             "activate browser check password",
             "activate browser check passwords",
             "activate browser check safety",
@@ -8545,7 +8523,6 @@
 
         // ID#8
         {
-            // Generated suggestions:
             "alter browse certificates",
             "alter browse enhanced protection",
             "alter browse safely",
@@ -9486,7 +9463,6 @@
 
         // ID#9
         {
-            // Generated suggestions:
             "all allow cookie settings",
             "all allow cookies",
             "all allow do not track",
@@ -9953,7 +9929,6 @@
 
         // ID#10
         {
-            // Generated suggestions:
             "add address",
             "add address browser",
             "add address chrome",
@@ -10998,7 +10973,6 @@
 
         // ID#11
         {
-            // Generated suggestions:
             "add sync",
             "add sync settings",
             "adjust sync",
@@ -11051,7 +11025,6 @@
 
         // ID#12
         {
-            // Generated suggestions:
             "adjust permissions",
             "adjust site permissions",
             "adjust site settings",
@@ -11116,7 +11089,6 @@
 
         // ID#13
         {
-            // Generated suggestions:
             "browser create doc",
             "browser create document",
             "browser doc create",
@@ -11601,7 +11573,6 @@
 
         // ID#14
         {
-            // Generated suggestions:
             "browser create sheet",
             "browser create sheets",
             "browser create spreadsheet",
@@ -12446,7 +12417,6 @@
 
         // ID#15
         {
-            // Generated suggestions:
             "browser create deck",
             "browser create presentation",
             "browser create preso",
@@ -13201,7 +13171,6 @@
 
         // ID#16
         {
-            // Generated suggestions:
             "add browser event",
             "add browser invite",
             "add browser meeting",
@@ -14088,1282 +14057,648 @@
 
         // ID#17
         {
-            // Generated suggestions:
-            "browser create site",
-            "browser create website",
-            "browser make site",
-            "browser make website",
-            "browser new site",
-            "browser new website",
-            "browser open site",
-            "browser open website",
-            "browser site create",
-            "browser site make",
-            "browser site new",
-            "browser site open",
-            "browser site start",
-            "browser start site",
-            "browser start website",
-            "browser website create",
-            "browser website make",
-            "browser website new",
-            "browser website open",
-            "browser website start",
-            "chrome create site",
-            "chrome create website",
-            "chrome make site",
-            "chrome make website",
-            "chrome new site",
-            "chrome new website",
-            "chrome open site",
-            "chrome open website",
-            "chrome site create",
-            "chrome site make",
-            "chrome site new",
-            "chrome site open",
-            "chrome site start",
-            "chrome start site",
-            "chrome start website",
-            "chrome website create",
-            "chrome website make",
-            "chrome website new",
-            "chrome website open",
-            "chrome website start",
-            "create browser site",
-            "create browser website",
-            "create chrome site",
-            "create chrome website",
-            "create g suite site",
-            "create g suite website",
-            "create google site",
-            "create google website",
-            "create site browser",
-            "create site chrome",
-            "create site g suite",
-            "create site google",
-            "create site workspace",
-            "create website browser",
-            "create website chrome",
-            "create website g suite",
-            "create website google",
-            "create website workspace",
-            "create workspace site",
-            "create workspace website",
-            "g suite create site",
-            "g suite create website",
-            "g suite make site",
-            "g suite make website",
-            "g suite new site",
-            "g suite new website",
-            "g suite open site",
-            "g suite open website",
-            "g suite site create",
-            "g suite site make",
-            "g suite site new",
-            "g suite site open",
-            "g suite site start",
-            "g suite start site",
-            "g suite start website",
-            "g suite website create",
-            "g suite website make",
-            "g suite website new",
-            "g suite website open",
-            "g suite website start",
-            "google create site",
-            "google create website",
-            "google make site",
-            "google make website",
-            "google new site",
-            "google new website",
-            "google open site",
-            "google open website",
-            "google site create",
-            "google site make",
-            "google site new",
-            "google site open",
-            "google site start",
-            "google start site",
-            "google start website",
-            "google website create",
-            "google website make",
-            "google website new",
-            "google website open",
-            "google website start",
-            "make browser site",
-            "make browser website",
-            "make chrome site",
-            "make chrome website",
-            "make g suite site",
-            "make g suite website",
-            "make google site",
-            "make google website",
-            "make site browser",
-            "make site chrome",
-            "make site g suite",
-            "make site google",
-            "make site workspace",
-            "make website browser",
-            "make website chrome",
-            "make website g suite",
-            "make website google",
-            "make website workspace",
-            "make workspace site",
-            "make workspace website",
-            "new browser site",
-            "new browser website",
-            "new chrome site",
-            "new chrome website",
-            "new g suite site",
-            "new g suite website",
-            "new google site",
-            "new google website",
-            "new site browser",
-            "new site chrome",
-            "new site g suite",
-            "new site google",
-            "new site workspace",
-            "new website browser",
-            "new website chrome",
-            "new website g suite",
-            "new website google",
-            "new website workspace",
-            "new workspace site",
-            "new workspace website",
-            "open browser site",
-            "open browser website",
-            "open chrome site",
-            "open chrome website",
-            "open g suite site",
-            "open g suite website",
-            "open google site",
-            "open google website",
-            "open site browser",
-            "open site chrome",
-            "open site g suite",
-            "open site google",
-            "open site workspace",
-            "open website browser",
-            "open website chrome",
-            "open website g suite",
-            "open website google",
-            "open website workspace",
-            "open workspace site",
-            "open workspace website",
-            "site browser create",
-            "site browser make",
-            "site browser new",
-            "site browser open",
-            "site browser start",
-            "site chrome create",
-            "site chrome make",
-            "site chrome new",
-            "site chrome open",
-            "site chrome start",
-            "site create browser",
-            "site create chrome",
-            "site create g suite",
-            "site create google",
-            "site create workspace",
-            "site g suite create",
-            "site g suite make",
-            "site g suite new",
-            "site g suite open",
-            "site g suite start",
-            "site google create",
-            "site google make",
-            "site google new",
-            "site google open",
-            "site google start",
-            "site make browser",
-            "site make chrome",
-            "site make g suite",
-            "site make google",
-            "site make workspace",
-            "site new browser",
-            "site new chrome",
-            "site new g suite",
-            "site new google",
-            "site new workspace",
-            "site open browser",
-            "site open chrome",
-            "site open g suite",
-            "site open google",
-            "site open workspace",
-            "site start browser",
-            "site start chrome",
-            "site start g suite",
-            "site start google",
-            "site start workspace",
-            "site workspace create",
-            "site workspace make",
-            "site workspace new",
-            "site workspace open",
-            "site workspace start",
-            "start browser site",
-            "start browser website",
-            "start chrome site",
-            "start chrome website",
-            "start g suite site",
-            "start g suite website",
-            "start google site",
-            "start google website",
-            "start site browser",
-            "start site chrome",
-            "start site g suite",
-            "start site google",
-            "start site workspace",
-            "start website browser",
-            "start website chrome",
-            "start website g suite",
-            "start website google",
-            "start website workspace",
-            "start workspace site",
-            "start workspace website",
-            "website browser create",
-            "website browser make",
-            "website browser new",
-            "website browser open",
-            "website browser start",
-            "website chrome create",
-            "website chrome make",
-            "website chrome new",
-            "website chrome open",
-            "website chrome start",
-            "website create browser",
-            "website create chrome",
-            "website create g suite",
-            "website create google",
-            "website create workspace",
-            "website g suite create",
-            "website g suite make",
-            "website g suite new",
-            "website g suite open",
-            "website g suite start",
-            "website google create",
-            "website google make",
-            "website google new",
-            "website google open",
-            "website google start",
-            "website make browser",
-            "website make chrome",
-            "website make g suite",
-            "website make google",
-            "website make workspace",
-            "website new browser",
-            "website new chrome",
-            "website new g suite",
-            "website new google",
-            "website new workspace",
-            "website open browser",
-            "website open chrome",
-            "website open g suite",
-            "website open google",
-            "website open workspace",
-            "website start browser",
-            "website start chrome",
-            "website start g suite",
-            "website start google",
-            "website start workspace",
-            "website workspace create",
-            "website workspace make",
-            "website workspace new",
-            "website workspace open",
-            "website workspace start",
-            "workspace create site",
-            "workspace create website",
-            "workspace make site",
-            "workspace make website",
-            "workspace new site",
-            "workspace new website",
-            "workspace open site",
-            "workspace open website",
-            "workspace site create",
-            "workspace site make",
-            "workspace site new",
-            "workspace site open",
-            "workspace site start",
-            "workspace start site",
-            "workspace start website",
-            "workspace website create",
-            "workspace website make",
-            "workspace website new",
-            "workspace website open",
-            "workspace website start",
+            "browser create site",      "browser create website",
+            "browser make site",        "browser make website",
+            "browser new site",         "browser new website",
+            "browser open site",        "browser open website",
+            "browser site create",      "browser site make",
+            "browser site new",         "browser site open",
+            "browser site start",       "browser start site",
+            "browser start website",    "browser website create",
+            "browser website make",     "browser website new",
+            "browser website open",     "browser website start",
+            "chrome create site",       "chrome create website",
+            "chrome make site",         "chrome make website",
+            "chrome new site",          "chrome new website",
+            "chrome open site",         "chrome open website",
+            "chrome site create",       "chrome site make",
+            "chrome site new",          "chrome site open",
+            "chrome site start",        "chrome start site",
+            "chrome start website",     "chrome website create",
+            "chrome website make",      "chrome website new",
+            "chrome website open",      "chrome website start",
+            "create browser site",      "create browser website",
+            "create chrome site",       "create chrome website",
+            "create g suite site",      "create g suite website",
+            "create google site",       "create google website",
+            "create site browser",      "create site chrome",
+            "create site g suite",      "create site google",
+            "create site workspace",    "create website browser",
+            "create website chrome",    "create website g suite",
+            "create website google",    "create website workspace",
+            "create workspace site",    "create workspace website",
+            "g suite create site",      "g suite create website",
+            "g suite make site",        "g suite make website",
+            "g suite new site",         "g suite new website",
+            "g suite open site",        "g suite open website",
+            "g suite site create",      "g suite site make",
+            "g suite site new",         "g suite site open",
+            "g suite site start",       "g suite start site",
+            "g suite start website",    "g suite website create",
+            "g suite website make",     "g suite website new",
+            "g suite website open",     "g suite website start",
+            "google create site",       "google create website",
+            "google make site",         "google make website",
+            "google new site",          "google new website",
+            "google open site",         "google open website",
+            "google site create",       "google site make",
+            "google site new",          "google site open",
+            "google site start",        "google start site",
+            "google start website",     "google website create",
+            "google website make",      "google website new",
+            "google website open",      "google website start",
+            "make browser site",        "make browser website",
+            "make chrome site",         "make chrome website",
+            "make g suite site",        "make g suite website",
+            "make google site",         "make google website",
+            "make site browser",        "make site chrome",
+            "make site g suite",        "make site google",
+            "make site workspace",      "make website browser",
+            "make website chrome",      "make website g suite",
+            "make website google",      "make website workspace",
+            "make workspace site",      "make workspace website",
+            "new browser site",         "new browser website",
+            "new chrome site",          "new chrome website",
+            "new g suite site",         "new g suite website",
+            "new google site",          "new google website",
+            "new site browser",         "new site chrome",
+            "new site g suite",         "new site google",
+            "new site workspace",       "new website browser",
+            "new website chrome",       "new website g suite",
+            "new website google",       "new website workspace",
+            "new workspace site",       "new workspace website",
+            "open browser site",        "open browser website",
+            "open chrome site",         "open chrome website",
+            "open g suite site",        "open g suite website",
+            "open google site",         "open google website",
+            "open site browser",        "open site chrome",
+            "open site g suite",        "open site google",
+            "open site workspace",      "open website browser",
+            "open website chrome",      "open website g suite",
+            "open website google",      "open website workspace",
+            "open workspace site",      "open workspace website",
+            "site browser create",      "site browser make",
+            "site browser new",         "site browser open",
+            "site browser start",       "site chrome create",
+            "site chrome make",         "site chrome new",
+            "site chrome open",         "site chrome start",
+            "site create browser",      "site create chrome",
+            "site create g suite",      "site create google",
+            "site create workspace",    "site g suite create",
+            "site g suite make",        "site g suite new",
+            "site g suite open",        "site g suite start",
+            "site google create",       "site google make",
+            "site google new",          "site google open",
+            "site google start",        "site make browser",
+            "site make chrome",         "site make g suite",
+            "site make google",         "site make workspace",
+            "site new browser",         "site new chrome",
+            "site new g suite",         "site new google",
+            "site new workspace",       "site open browser",
+            "site open chrome",         "site open g suite",
+            "site open google",         "site open workspace",
+            "site start browser",       "site start chrome",
+            "site start g suite",       "site start google",
+            "site start workspace",     "site workspace create",
+            "site workspace make",      "site workspace new",
+            "site workspace open",      "site workspace start",
+            "start browser site",       "start browser website",
+            "start chrome site",        "start chrome website",
+            "start g suite site",       "start g suite website",
+            "start google site",        "start google website",
+            "start site browser",       "start site chrome",
+            "start site g suite",       "start site google",
+            "start site workspace",     "start website browser",
+            "start website chrome",     "start website g suite",
+            "start website google",     "start website workspace",
+            "start workspace site",     "start workspace website",
+            "website browser create",   "website browser make",
+            "website browser new",      "website browser open",
+            "website browser start",    "website chrome create",
+            "website chrome make",      "website chrome new",
+            "website chrome open",      "website chrome start",
+            "website create browser",   "website create chrome",
+            "website create g suite",   "website create google",
+            "website create workspace", "website g suite create",
+            "website g suite make",     "website g suite new",
+            "website g suite open",     "website g suite start",
+            "website google create",    "website google make",
+            "website google new",       "website google open",
+            "website google start",     "website make browser",
+            "website make chrome",      "website make g suite",
+            "website make google",      "website make workspace",
+            "website new browser",      "website new chrome",
+            "website new g suite",      "website new google",
+            "website new workspace",    "website open browser",
+            "website open chrome",      "website open g suite",
+            "website open google",      "website open workspace",
+            "website start browser",    "website start chrome",
+            "website start g suite",    "website start google",
+            "website start workspace",  "website workspace create",
+            "website workspace make",   "website workspace new",
+            "website workspace open",   "website workspace start",
+            "workspace create site",    "workspace create website",
+            "workspace make site",      "workspace make website",
+            "workspace new site",       "workspace new website",
+            "workspace open site",      "workspace open website",
+            "workspace site create",    "workspace site make",
+            "workspace site new",       "workspace site open",
+            "workspace site start",     "workspace start site",
+            "workspace start website",  "workspace website create",
+            "workspace website make",   "workspace website new",
+            "workspace website open",   "workspace website start",
         },
 
         // ID#18
         {
-            // Generated suggestions:
-            "browser create note",
-            "browser create notes",
-            "browser make note",
-            "browser make notes",
-            "browser new note",
-            "browser new notes",
-            "browser note create",
-            "browser note make",
-            "browser note new",
-            "browser note open",
-            "browser note start",
-            "browser notes create",
-            "browser notes make",
-            "browser notes new",
-            "browser notes open",
-            "browser notes start",
-            "browser open note",
-            "browser open notes",
-            "browser start note",
-            "browser start notes",
-            "chrome create note",
-            "chrome create notes",
-            "chrome make note",
-            "chrome make notes",
-            "chrome new note",
-            "chrome new notes",
-            "chrome note create",
-            "chrome note make",
-            "chrome note new",
-            "chrome note open",
-            "chrome note start",
-            "chrome notes create",
-            "chrome notes make",
-            "chrome notes new",
-            "chrome notes open",
-            "chrome notes start",
-            "chrome open note",
-            "chrome open notes",
-            "chrome start note",
-            "chrome start notes",
-            "create browser note",
-            "create browser notes",
-            "create chrome note",
-            "create chrome notes",
-            "create g suite note",
-            "create g suite notes",
-            "create google note",
-            "create google notes",
-            "create keep note",
-            "create keep notes",
-            "create note browser",
-            "create note chrome",
-            "create note g suite",
-            "create note google",
-            "create note keep",
-            "create note workspace",
-            "create notes browser",
-            "create notes chrome",
-            "create notes g suite",
-            "create notes google",
-            "create notes keep",
-            "create notes workspace",
-            "create workspace note",
-            "create workspace notes",
-            "g suite create note",
-            "g suite create notes",
-            "g suite make note",
-            "g suite make notes",
-            "g suite new note",
-            "g suite new notes",
-            "g suite note create",
-            "g suite note make",
-            "g suite note new",
-            "g suite note open",
-            "g suite note start",
-            "g suite notes create",
-            "g suite notes make",
-            "g suite notes new",
-            "g suite notes open",
-            "g suite notes start",
-            "g suite open note",
-            "g suite open notes",
-            "g suite start note",
-            "g suite start notes",
-            "google create note",
-            "google create notes",
-            "google make note",
-            "google make notes",
-            "google new note",
-            "google new notes",
-            "google note create",
-            "google note make",
-            "google note new",
-            "google note open",
-            "google note start",
-            "google notes create",
-            "google notes make",
-            "google notes new",
-            "google notes open",
-            "google notes start",
-            "google open note",
-            "google open notes",
-            "google start note",
-            "google start notes",
-            "keep create note",
-            "keep create notes",
-            "keep make note",
-            "keep make notes",
-            "keep new note",
-            "keep new notes",
-            "keep note create",
-            "keep note make",
-            "keep note new",
-            "keep note open",
-            "keep note start",
-            "keep notes create",
-            "keep notes make",
-            "keep notes new",
-            "keep notes open",
-            "keep notes start",
-            "keep open note",
-            "keep open notes",
-            "keep start note",
-            "keep start notes",
-            "make browser note",
-            "make browser notes",
-            "make chrome note",
-            "make chrome notes",
-            "make g suite note",
-            "make g suite notes",
-            "make google note",
-            "make google notes",
-            "make keep note",
-            "make keep notes",
-            "make note browser",
-            "make note chrome",
-            "make note g suite",
-            "make note google",
-            "make note keep",
-            "make note workspace",
-            "make notes browser",
-            "make notes chrome",
-            "make notes g suite",
-            "make notes google",
-            "make notes keep",
-            "make notes workspace",
-            "make workspace note",
-            "make workspace notes",
-            "new browser note",
-            "new browser notes",
-            "new chrome note",
-            "new chrome notes",
-            "new g suite note",
-            "new g suite notes",
-            "new google note",
-            "new google notes",
-            "new keep note",
-            "new keep notes",
-            "new note browser",
-            "new note chrome",
-            "new note g suite",
-            "new note google",
-            "new note keep",
-            "new note workspace",
-            "new notes browser",
-            "new notes chrome",
-            "new notes g suite",
-            "new notes google",
-            "new notes keep",
-            "new notes workspace",
-            "new workspace note",
-            "new workspace notes",
-            "note browser create",
-            "note browser make",
-            "note browser new",
-            "note browser open",
-            "note browser start",
-            "note chrome create",
-            "note chrome make",
-            "note chrome new",
-            "note chrome open",
-            "note chrome start",
-            "note create browser",
-            "note create chrome",
-            "note create g suite",
-            "note create google",
-            "note create keep",
-            "note create workspace",
-            "note g suite create",
-            "note g suite make",
-            "note g suite new",
-            "note g suite open",
-            "note g suite start",
-            "note google create",
-            "note google make",
-            "note google new",
-            "note google open",
-            "note google start",
-            "note keep create",
-            "note keep make",
-            "note keep new",
-            "note keep open",
-            "note keep start",
-            "note make browser",
-            "note make chrome",
-            "note make g suite",
-            "note make google",
-            "note make keep",
-            "note make workspace",
-            "note new browser",
-            "note new chrome",
-            "note new g suite",
-            "note new google",
-            "note new keep",
-            "note new workspace",
-            "note open browser",
-            "note open chrome",
-            "note open g suite",
-            "note open google",
-            "note open keep",
-            "note open workspace",
-            "note start browser",
-            "note start chrome",
-            "note start g suite",
-            "note start google",
-            "note start keep",
-            "note start workspace",
-            "note workspace create",
-            "note workspace make",
-            "note workspace new",
-            "note workspace open",
-            "note workspace start",
-            "notes browser create",
-            "notes browser make",
-            "notes browser new",
-            "notes browser open",
-            "notes browser start",
-            "notes chrome create",
-            "notes chrome make",
-            "notes chrome new",
-            "notes chrome open",
-            "notes chrome start",
-            "notes create browser",
-            "notes create chrome",
-            "notes create g suite",
-            "notes create google",
-            "notes create keep",
-            "notes create workspace",
-            "notes g suite create",
-            "notes g suite make",
-            "notes g suite new",
-            "notes g suite open",
-            "notes g suite start",
-            "notes google create",
-            "notes google make",
-            "notes google new",
-            "notes google open",
-            "notes google start",
-            "notes keep create",
-            "notes keep make",
-            "notes keep new",
-            "notes keep open",
-            "notes keep start",
-            "notes make browser",
-            "notes make chrome",
-            "notes make g suite",
-            "notes make google",
-            "notes make keep",
-            "notes make workspace",
-            "notes new browser",
-            "notes new chrome",
-            "notes new g suite",
-            "notes new google",
-            "notes new keep",
-            "notes new workspace",
-            "notes open browser",
-            "notes open chrome",
-            "notes open g suite",
-            "notes open google",
-            "notes open keep",
-            "notes open workspace",
-            "notes start browser",
-            "notes start chrome",
-            "notes start g suite",
-            "notes start google",
-            "notes start keep",
-            "notes start workspace",
-            "notes workspace create",
-            "notes workspace make",
-            "notes workspace new",
-            "notes workspace open",
-            "notes workspace start",
-            "open browser note",
-            "open browser notes",
-            "open chrome note",
-            "open chrome notes",
-            "open g suite note",
-            "open g suite notes",
-            "open google note",
-            "open google notes",
-            "open keep note",
-            "open keep notes",
-            "open note browser",
-            "open note chrome",
-            "open note g suite",
-            "open note google",
-            "open note keep",
-            "open note workspace",
-            "open notes browser",
-            "open notes chrome",
-            "open notes g suite",
-            "open notes google",
-            "open notes keep",
-            "open notes workspace",
-            "open workspace note",
-            "open workspace notes",
-            "start browser note",
-            "start browser notes",
-            "start chrome note",
-            "start chrome notes",
-            "start g suite note",
-            "start g suite notes",
-            "start google note",
-            "start google notes",
-            "start keep note",
-            "start keep notes",
-            "start note browser",
-            "start note chrome",
-            "start note g suite",
-            "start note google",
-            "start note keep",
-            "start note workspace",
-            "start notes browser",
-            "start notes chrome",
-            "start notes g suite",
-            "start notes google",
-            "start notes keep",
-            "start notes workspace",
-            "start workspace note",
-            "start workspace notes",
-            "workspace create note",
-            "workspace create notes",
-            "workspace make note",
-            "workspace make notes",
-            "workspace new note",
-            "workspace new notes",
-            "workspace note create",
-            "workspace note make",
-            "workspace note new",
-            "workspace note open",
-            "workspace note start",
-            "workspace notes create",
-            "workspace notes make",
-            "workspace notes new",
-            "workspace notes open",
-            "workspace notes start",
-            "workspace open note",
-            "workspace open notes",
-            "workspace start note",
-            "workspace start notes",
+            "browser create note",   "browser create notes",
+            "browser make note",     "browser make notes",
+            "browser new note",      "browser new notes",
+            "browser note create",   "browser note make",
+            "browser note new",      "browser note open",
+            "browser note start",    "browser notes create",
+            "browser notes make",    "browser notes new",
+            "browser notes open",    "browser notes start",
+            "browser open note",     "browser open notes",
+            "browser start note",    "browser start notes",
+            "chrome create note",    "chrome create notes",
+            "chrome make note",      "chrome make notes",
+            "chrome new note",       "chrome new notes",
+            "chrome note create",    "chrome note make",
+            "chrome note new",       "chrome note open",
+            "chrome note start",     "chrome notes create",
+            "chrome notes make",     "chrome notes new",
+            "chrome notes open",     "chrome notes start",
+            "chrome open note",      "chrome open notes",
+            "chrome start note",     "chrome start notes",
+            "create browser note",   "create browser notes",
+            "create chrome note",    "create chrome notes",
+            "create g suite note",   "create g suite notes",
+            "create google note",    "create google notes",
+            "create keep note",      "create keep notes",
+            "create note browser",   "create note chrome",
+            "create note g suite",   "create note google",
+            "create note keep",      "create note workspace",
+            "create notes browser",  "create notes chrome",
+            "create notes g suite",  "create notes google",
+            "create notes keep",     "create notes workspace",
+            "create workspace note", "create workspace notes",
+            "g suite create note",   "g suite create notes",
+            "g suite make note",     "g suite make notes",
+            "g suite new note",      "g suite new notes",
+            "g suite note create",   "g suite note make",
+            "g suite note new",      "g suite note open",
+            "g suite note start",    "g suite notes create",
+            "g suite notes make",    "g suite notes new",
+            "g suite notes open",    "g suite notes start",
+            "g suite open note",     "g suite open notes",
+            "g suite start note",    "g suite start notes",
+            "google create note",    "google create notes",
+            "google make note",      "google make notes",
+            "google new note",       "google new notes",
+            "google note create",    "google note make",
+            "google note new",       "google note open",
+            "google note start",     "google notes create",
+            "google notes make",     "google notes new",
+            "google notes open",     "google notes start",
+            "google open note",      "google open notes",
+            "google start note",     "google start notes",
+            "keep create note",      "keep create notes",
+            "keep make note",        "keep make notes",
+            "keep new note",         "keep new notes",
+            "keep note create",      "keep note make",
+            "keep note new",         "keep note open",
+            "keep note start",       "keep notes create",
+            "keep notes make",       "keep notes new",
+            "keep notes open",       "keep notes start",
+            "keep open note",        "keep open notes",
+            "keep start note",       "keep start notes",
+            "make browser note",     "make browser notes",
+            "make chrome note",      "make chrome notes",
+            "make g suite note",     "make g suite notes",
+            "make google note",      "make google notes",
+            "make keep note",        "make keep notes",
+            "make note browser",     "make note chrome",
+            "make note g suite",     "make note google",
+            "make note keep",        "make note workspace",
+            "make notes browser",    "make notes chrome",
+            "make notes g suite",    "make notes google",
+            "make notes keep",       "make notes workspace",
+            "make workspace note",   "make workspace notes",
+            "new browser note",      "new browser notes",
+            "new chrome note",       "new chrome notes",
+            "new g suite note",      "new g suite notes",
+            "new google note",       "new google notes",
+            "new keep note",         "new keep notes",
+            "new note browser",      "new note chrome",
+            "new note g suite",      "new note google",
+            "new note keep",         "new note workspace",
+            "new notes browser",     "new notes chrome",
+            "new notes g suite",     "new notes google",
+            "new notes keep",        "new notes workspace",
+            "new workspace note",    "new workspace notes",
+            "note browser create",   "note browser make",
+            "note browser new",      "note browser open",
+            "note browser start",    "note chrome create",
+            "note chrome make",      "note chrome new",
+            "note chrome open",      "note chrome start",
+            "note create browser",   "note create chrome",
+            "note create g suite",   "note create google",
+            "note create keep",      "note create workspace",
+            "note g suite create",   "note g suite make",
+            "note g suite new",      "note g suite open",
+            "note g suite start",    "note google create",
+            "note google make",      "note google new",
+            "note google open",      "note google start",
+            "note keep create",      "note keep make",
+            "note keep new",         "note keep open",
+            "note keep start",       "note make browser",
+            "note make chrome",      "note make g suite",
+            "note make google",      "note make keep",
+            "note make workspace",   "note new browser",
+            "note new chrome",       "note new g suite",
+            "note new google",       "note new keep",
+            "note new workspace",    "note open browser",
+            "note open chrome",      "note open g suite",
+            "note open google",      "note open keep",
+            "note open workspace",   "note start browser",
+            "note start chrome",     "note start g suite",
+            "note start google",     "note start keep",
+            "note start workspace",  "note workspace create",
+            "note workspace make",   "note workspace new",
+            "note workspace open",   "note workspace start",
+            "notes browser create",  "notes browser make",
+            "notes browser new",     "notes browser open",
+            "notes browser start",   "notes chrome create",
+            "notes chrome make",     "notes chrome new",
+            "notes chrome open",     "notes chrome start",
+            "notes create browser",  "notes create chrome",
+            "notes create g suite",  "notes create google",
+            "notes create keep",     "notes create workspace",
+            "notes g suite create",  "notes g suite make",
+            "notes g suite new",     "notes g suite open",
+            "notes g suite start",   "notes google create",
+            "notes google make",     "notes google new",
+            "notes google open",     "notes google start",
+            "notes keep create",     "notes keep make",
+            "notes keep new",        "notes keep open",
+            "notes keep start",      "notes make browser",
+            "notes make chrome",     "notes make g suite",
+            "notes make google",     "notes make keep",
+            "notes make workspace",  "notes new browser",
+            "notes new chrome",      "notes new g suite",
+            "notes new google",      "notes new keep",
+            "notes new workspace",   "notes open browser",
+            "notes open chrome",     "notes open g suite",
+            "notes open google",     "notes open keep",
+            "notes open workspace",  "notes start browser",
+            "notes start chrome",    "notes start g suite",
+            "notes start google",    "notes start keep",
+            "notes start workspace", "notes workspace create",
+            "notes workspace make",  "notes workspace new",
+            "notes workspace open",  "notes workspace start",
+            "open browser note",     "open browser notes",
+            "open chrome note",      "open chrome notes",
+            "open g suite note",     "open g suite notes",
+            "open google note",      "open google notes",
+            "open keep note",        "open keep notes",
+            "open note browser",     "open note chrome",
+            "open note g suite",     "open note google",
+            "open note keep",        "open note workspace",
+            "open notes browser",    "open notes chrome",
+            "open notes g suite",    "open notes google",
+            "open notes keep",       "open notes workspace",
+            "open workspace note",   "open workspace notes",
+            "start browser note",    "start browser notes",
+            "start chrome note",     "start chrome notes",
+            "start g suite note",    "start g suite notes",
+            "start google note",     "start google notes",
+            "start keep note",       "start keep notes",
+            "start note browser",    "start note chrome",
+            "start note g suite",    "start note google",
+            "start note keep",       "start note workspace",
+            "start notes browser",   "start notes chrome",
+            "start notes g suite",   "start notes google",
+            "start notes keep",      "start notes workspace",
+            "start workspace note",  "start workspace notes",
+            "workspace create note", "workspace create notes",
+            "workspace make note",   "workspace make notes",
+            "workspace new note",    "workspace new notes",
+            "workspace note create", "workspace note make",
+            "workspace note new",    "workspace note open",
+            "workspace note start",  "workspace notes create",
+            "workspace notes make",  "workspace notes new",
+            "workspace notes open",  "workspace notes start",
+            "workspace open note",   "workspace open notes",
+            "workspace start note",  "workspace start notes",
         },
 
         // ID#19
         {
-            // Generated suggestions:
-            "browser create form",
-            "browser create forms",
-            "browser create quiz",
-            "browser create survey",
-            "browser form create",
-            "browser form make",
-            "browser form new",
-            "browser form open",
-            "browser form start",
-            "browser forms create",
-            "browser forms make",
-            "browser forms new",
-            "browser forms open",
-            "browser forms start",
-            "browser make form",
-            "browser make forms",
-            "browser make quiz",
-            "browser make survey",
-            "browser new form",
-            "browser new forms",
-            "browser new quiz",
-            "browser new survey",
-            "browser open form",
-            "browser open forms",
-            "browser open quiz",
-            "browser open survey",
-            "browser quiz create",
-            "browser quiz make",
-            "browser quiz new",
-            "browser quiz open",
-            "browser quiz start",
-            "browser start form",
-            "browser start forms",
-            "browser start quiz",
-            "browser start survey",
-            "browser survey create",
-            "browser survey make",
-            "browser survey new",
-            "browser survey open",
-            "browser survey start",
-            "chrome create form",
-            "chrome create forms",
-            "chrome create quiz",
-            "chrome create survey",
-            "chrome form create",
-            "chrome form make",
-            "chrome form new",
-            "chrome form open",
-            "chrome form start",
-            "chrome forms create",
-            "chrome forms make",
-            "chrome forms new",
-            "chrome forms open",
-            "chrome forms start",
-            "chrome make form",
-            "chrome make forms",
-            "chrome make quiz",
-            "chrome make survey",
-            "chrome new form",
-            "chrome new forms",
-            "chrome new quiz",
-            "chrome new survey",
-            "chrome open form",
-            "chrome open forms",
-            "chrome open quiz",
-            "chrome open survey",
-            "chrome quiz create",
-            "chrome quiz make",
-            "chrome quiz new",
-            "chrome quiz open",
-            "chrome quiz start",
-            "chrome start form",
-            "chrome start forms",
-            "chrome start quiz",
-            "chrome start survey",
-            "chrome survey create",
-            "chrome survey make",
-            "chrome survey new",
-            "chrome survey open",
-            "chrome survey start",
-            "create browser form",
-            "create browser forms",
-            "create browser quiz",
-            "create browser survey",
-            "create chrome form",
-            "create chrome forms",
-            "create chrome quiz",
-            "create chrome survey",
-            "create form browser",
-            "create form chrome",
-            "create form g suite",
-            "create form google",
-            "create form workspace",
-            "create forms browser",
-            "create forms chrome",
-            "create forms g suite",
-            "create forms google",
-            "create forms workspace",
-            "create g suite form",
-            "create g suite forms",
-            "create g suite quiz",
-            "create g suite survey",
-            "create google form",
-            "create google forms",
-            "create google quiz",
-            "create google survey",
-            "create quiz browser",
-            "create quiz chrome",
-            "create quiz g suite",
-            "create quiz google",
-            "create quiz workspace",
-            "create survey browser",
-            "create survey chrome",
-            "create survey g suite",
-            "create survey google",
-            "create survey workspace",
-            "create workspace form",
-            "create workspace forms",
-            "create workspace quiz",
-            "create workspace survey",
-            "form browser create",
-            "form browser make",
-            "form browser new",
-            "form browser open",
-            "form browser start",
-            "form chrome create",
-            "form chrome make",
-            "form chrome new",
-            "form chrome open",
-            "form chrome start",
-            "form create browser",
-            "form create chrome",
-            "form create g suite",
-            "form create google",
-            "form create workspace",
-            "form g suite create",
-            "form g suite make",
-            "form g suite new",
-            "form g suite open",
-            "form g suite start",
-            "form google create",
-            "form google make",
-            "form google new",
-            "form google open",
-            "form google start",
-            "form make browser",
-            "form make chrome",
-            "form make g suite",
-            "form make google",
-            "form make workspace",
-            "form new browser",
-            "form new chrome",
-            "form new g suite",
-            "form new google",
-            "form new workspace",
-            "form open browser",
-            "form open chrome",
-            "form open g suite",
-            "form open google",
-            "form open workspace",
-            "form start browser",
-            "form start chrome",
-            "form start g suite",
-            "form start google",
-            "form start workspace",
-            "form workspace create",
-            "form workspace make",
-            "form workspace new",
-            "form workspace open",
-            "form workspace start",
-            "forms browser create",
-            "forms browser make",
-            "forms browser new",
-            "forms browser open",
-            "forms browser start",
-            "forms chrome create",
-            "forms chrome make",
-            "forms chrome new",
-            "forms chrome open",
-            "forms chrome start",
-            "forms create browser",
-            "forms create chrome",
-            "forms create g suite",
-            "forms create google",
-            "forms create workspace",
-            "forms g suite create",
-            "forms g suite make",
-            "forms g suite new",
-            "forms g suite open",
-            "forms g suite start",
-            "forms google create",
-            "forms google make",
-            "forms google new",
-            "forms google open",
-            "forms google start",
-            "forms make browser",
-            "forms make chrome",
-            "forms make g suite",
-            "forms make google",
-            "forms make workspace",
-            "forms new browser",
-            "forms new chrome",
-            "forms new g suite",
-            "forms new google",
-            "forms new workspace",
-            "forms open browser",
-            "forms open chrome",
-            "forms open g suite",
-            "forms open google",
-            "forms open workspace",
-            "forms start browser",
-            "forms start chrome",
-            "forms start g suite",
-            "forms start google",
-            "forms start workspace",
-            "forms workspace create",
-            "forms workspace make",
-            "forms workspace new",
-            "forms workspace open",
-            "forms workspace start",
-            "g suite create form",
-            "g suite create forms",
-            "g suite create quiz",
-            "g suite create survey",
-            "g suite form create",
-            "g suite form make",
-            "g suite form new",
-            "g suite form open",
-            "g suite form start",
-            "g suite forms create",
-            "g suite forms make",
-            "g suite forms new",
-            "g suite forms open",
-            "g suite forms start",
-            "g suite make form",
-            "g suite make forms",
-            "g suite make quiz",
-            "g suite make survey",
-            "g suite new form",
-            "g suite new forms",
-            "g suite new quiz",
-            "g suite new survey",
-            "g suite open form",
-            "g suite open forms",
-            "g suite open quiz",
-            "g suite open survey",
-            "g suite quiz create",
-            "g suite quiz make",
-            "g suite quiz new",
-            "g suite quiz open",
-            "g suite quiz start",
-            "g suite start form",
-            "g suite start forms",
-            "g suite start quiz",
-            "g suite start survey",
-            "g suite survey create",
-            "g suite survey make",
-            "g suite survey new",
-            "g suite survey open",
-            "g suite survey start",
-            "google create form",
-            "google create forms",
-            "google create quiz",
-            "google create survey",
-            "google form create",
-            "google form make",
-            "google form new",
-            "google form open",
-            "google form start",
-            "google forms create",
-            "google forms make",
-            "google forms new",
-            "google forms open",
-            "google forms start",
-            "google make form",
-            "google make forms",
-            "google make quiz",
-            "google make survey",
-            "google new form",
-            "google new forms",
-            "google new quiz",
-            "google new survey",
-            "google open form",
-            "google open forms",
-            "google open quiz",
-            "google open survey",
-            "google quiz create",
-            "google quiz make",
-            "google quiz new",
-            "google quiz open",
-            "google quiz start",
-            "google start form",
-            "google start forms",
-            "google start quiz",
-            "google start survey",
-            "google survey create",
-            "google survey make",
-            "google survey new",
-            "google survey open",
-            "google survey start",
-            "make browser form",
-            "make browser forms",
-            "make browser quiz",
-            "make browser survey",
-            "make chrome form",
-            "make chrome forms",
-            "make chrome quiz",
-            "make chrome survey",
-            "make form browser",
-            "make form chrome",
-            "make form g suite",
-            "make form google",
-            "make form workspace",
-            "make forms browser",
-            "make forms chrome",
-            "make forms g suite",
-            "make forms google",
-            "make forms workspace",
-            "make g suite form",
-            "make g suite forms",
-            "make g suite quiz",
-            "make g suite survey",
-            "make google form",
-            "make google forms",
-            "make google quiz",
-            "make google survey",
-            "make quiz browser",
-            "make quiz chrome",
-            "make quiz g suite",
-            "make quiz google",
-            "make quiz workspace",
-            "make survey browser",
-            "make survey chrome",
-            "make survey g suite",
-            "make survey google",
-            "make survey workspace",
-            "make workspace form",
-            "make workspace forms",
-            "make workspace quiz",
-            "make workspace survey",
-            "new browser form",
-            "new browser forms",
-            "new browser quiz",
-            "new browser survey",
-            "new chrome form",
-            "new chrome forms",
-            "new chrome quiz",
-            "new chrome survey",
-            "new form browser",
-            "new form chrome",
-            "new form g suite",
-            "new form google",
-            "new form workspace",
-            "new forms browser",
-            "new forms chrome",
-            "new forms g suite",
-            "new forms google",
-            "new forms workspace",
-            "new g suite form",
-            "new g suite forms",
-            "new g suite quiz",
-            "new g suite survey",
-            "new google form",
-            "new google forms",
-            "new google quiz",
-            "new google survey",
-            "new quiz browser",
-            "new quiz chrome",
-            "new quiz g suite",
-            "new quiz google",
-            "new quiz workspace",
-            "new survey browser",
-            "new survey chrome",
-            "new survey g suite",
-            "new survey google",
-            "new survey workspace",
-            "new workspace form",
-            "new workspace forms",
-            "new workspace quiz",
-            "new workspace survey",
-            "open browser form",
-            "open browser forms",
-            "open browser quiz",
-            "open browser survey",
-            "open chrome form",
-            "open chrome forms",
-            "open chrome quiz",
-            "open chrome survey",
-            "open form browser",
-            "open form chrome",
-            "open form g suite",
-            "open form google",
-            "open form workspace",
-            "open forms browser",
-            "open forms chrome",
-            "open forms g suite",
-            "open forms google",
-            "open forms workspace",
-            "open g suite form",
-            "open g suite forms",
-            "open g suite quiz",
-            "open g suite survey",
-            "open google form",
-            "open google forms",
-            "open google quiz",
-            "open google survey",
-            "open quiz browser",
-            "open quiz chrome",
-            "open quiz g suite",
-            "open quiz google",
-            "open quiz workspace",
-            "open survey browser",
-            "open survey chrome",
-            "open survey g suite",
-            "open survey google",
-            "open survey workspace",
-            "open workspace form",
-            "open workspace forms",
-            "open workspace quiz",
-            "open workspace survey",
-            "quiz browser create",
-            "quiz browser make",
-            "quiz browser new",
-            "quiz browser open",
-            "quiz browser start",
-            "quiz chrome create",
-            "quiz chrome make",
-            "quiz chrome new",
-            "quiz chrome open",
-            "quiz chrome start",
-            "quiz create browser",
-            "quiz create chrome",
-            "quiz create g suite",
-            "quiz create google",
-            "quiz create workspace",
-            "quiz g suite create",
-            "quiz g suite make",
-            "quiz g suite new",
-            "quiz g suite open",
-            "quiz g suite start",
-            "quiz google create",
-            "quiz google make",
-            "quiz google new",
-            "quiz google open",
-            "quiz google start",
-            "quiz make browser",
-            "quiz make chrome",
-            "quiz make g suite",
-            "quiz make google",
-            "quiz make workspace",
-            "quiz new browser",
-            "quiz new chrome",
-            "quiz new g suite",
-            "quiz new google",
-            "quiz new workspace",
-            "quiz open browser",
-            "quiz open chrome",
-            "quiz open g suite",
-            "quiz open google",
-            "quiz open workspace",
-            "quiz start browser",
-            "quiz start chrome",
-            "quiz start g suite",
-            "quiz start google",
-            "quiz start workspace",
-            "quiz workspace create",
-            "quiz workspace make",
-            "quiz workspace new",
-            "quiz workspace open",
-            "quiz workspace start",
-            "start browser form",
-            "start browser forms",
-            "start browser quiz",
-            "start browser survey",
-            "start chrome form",
-            "start chrome forms",
-            "start chrome quiz",
-            "start chrome survey",
-            "start form browser",
-            "start form chrome",
-            "start form g suite",
-            "start form google",
-            "start form workspace",
-            "start forms browser",
-            "start forms chrome",
-            "start forms g suite",
-            "start forms google",
-            "start forms workspace",
-            "start g suite form",
-            "start g suite forms",
-            "start g suite quiz",
-            "start g suite survey",
-            "start google form",
-            "start google forms",
-            "start google quiz",
-            "start google survey",
-            "start quiz browser",
-            "start quiz chrome",
-            "start quiz g suite",
-            "start quiz google",
-            "start quiz workspace",
-            "start survey browser",
-            "start survey chrome",
-            "start survey g suite",
-            "start survey google",
-            "start survey workspace",
-            "start workspace form",
-            "start workspace forms",
-            "start workspace quiz",
-            "start workspace survey",
-            "survey browser create",
-            "survey browser make",
-            "survey browser new",
-            "survey browser open",
-            "survey browser start",
-            "survey chrome create",
-            "survey chrome make",
-            "survey chrome new",
-            "survey chrome open",
-            "survey chrome start",
-            "survey create browser",
-            "survey create chrome",
-            "survey create g suite",
-            "survey create google",
-            "survey create workspace",
-            "survey g suite create",
-            "survey g suite make",
-            "survey g suite new",
-            "survey g suite open",
-            "survey g suite start",
-            "survey google create",
-            "survey google make",
-            "survey google new",
-            "survey google open",
-            "survey google start",
-            "survey make browser",
-            "survey make chrome",
-            "survey make g suite",
-            "survey make google",
-            "survey make workspace",
-            "survey new browser",
-            "survey new chrome",
-            "survey new g suite",
-            "survey new google",
-            "survey new workspace",
-            "survey open browser",
-            "survey open chrome",
-            "survey open g suite",
-            "survey open google",
-            "survey open workspace",
-            "survey start browser",
-            "survey start chrome",
-            "survey start g suite",
-            "survey start google",
-            "survey start workspace",
-            "survey workspace create",
-            "survey workspace make",
-            "survey workspace new",
-            "survey workspace open",
-            "survey workspace start",
-            "workspace create form",
-            "workspace create forms",
-            "workspace create quiz",
-            "workspace create survey",
-            "workspace form create",
-            "workspace form make",
-            "workspace form new",
-            "workspace form open",
-            "workspace form start",
-            "workspace forms create",
-            "workspace forms make",
-            "workspace forms new",
-            "workspace forms open",
-            "workspace forms start",
-            "workspace make form",
-            "workspace make forms",
-            "workspace make quiz",
-            "workspace make survey",
-            "workspace new form",
-            "workspace new forms",
-            "workspace new quiz",
-            "workspace new survey",
-            "workspace open form",
-            "workspace open forms",
-            "workspace open quiz",
-            "workspace open survey",
-            "workspace quiz create",
-            "workspace quiz make",
-            "workspace quiz new",
-            "workspace quiz open",
-            "workspace quiz start",
-            "workspace start form",
-            "workspace start forms",
-            "workspace start quiz",
-            "workspace start survey",
-            "workspace survey create",
-            "workspace survey make",
-            "workspace survey new",
-            "workspace survey open",
-            "workspace survey start",
+            "browser create form",     "browser create forms",
+            "browser create quiz",     "browser create survey",
+            "browser form create",     "browser form make",
+            "browser form new",        "browser form open",
+            "browser form start",      "browser forms create",
+            "browser forms make",      "browser forms new",
+            "browser forms open",      "browser forms start",
+            "browser make form",       "browser make forms",
+            "browser make quiz",       "browser make survey",
+            "browser new form",        "browser new forms",
+            "browser new quiz",        "browser new survey",
+            "browser open form",       "browser open forms",
+            "browser open quiz",       "browser open survey",
+            "browser quiz create",     "browser quiz make",
+            "browser quiz new",        "browser quiz open",
+            "browser quiz start",      "browser start form",
+            "browser start forms",     "browser start quiz",
+            "browser start survey",    "browser survey create",
+            "browser survey make",     "browser survey new",
+            "browser survey open",     "browser survey start",
+            "chrome create form",      "chrome create forms",
+            "chrome create quiz",      "chrome create survey",
+            "chrome form create",      "chrome form make",
+            "chrome form new",         "chrome form open",
+            "chrome form start",       "chrome forms create",
+            "chrome forms make",       "chrome forms new",
+            "chrome forms open",       "chrome forms start",
+            "chrome make form",        "chrome make forms",
+            "chrome make quiz",        "chrome make survey",
+            "chrome new form",         "chrome new forms",
+            "chrome new quiz",         "chrome new survey",
+            "chrome open form",        "chrome open forms",
+            "chrome open quiz",        "chrome open survey",
+            "chrome quiz create",      "chrome quiz make",
+            "chrome quiz new",         "chrome quiz open",
+            "chrome quiz start",       "chrome start form",
+            "chrome start forms",      "chrome start quiz",
+            "chrome start survey",     "chrome survey create",
+            "chrome survey make",      "chrome survey new",
+            "chrome survey open",      "chrome survey start",
+            "create browser form",     "create browser forms",
+            "create browser quiz",     "create browser survey",
+            "create chrome form",      "create chrome forms",
+            "create chrome quiz",      "create chrome survey",
+            "create form browser",     "create form chrome",
+            "create form g suite",     "create form google",
+            "create form workspace",   "create forms browser",
+            "create forms chrome",     "create forms g suite",
+            "create forms google",     "create forms workspace",
+            "create g suite form",     "create g suite forms",
+            "create g suite quiz",     "create g suite survey",
+            "create google form",      "create google forms",
+            "create google quiz",      "create google survey",
+            "create quiz browser",     "create quiz chrome",
+            "create quiz g suite",     "create quiz google",
+            "create quiz workspace",   "create survey browser",
+            "create survey chrome",    "create survey g suite",
+            "create survey google",    "create survey workspace",
+            "create workspace form",   "create workspace forms",
+            "create workspace quiz",   "create workspace survey",
+            "form browser create",     "form browser make",
+            "form browser new",        "form browser open",
+            "form browser start",      "form chrome create",
+            "form chrome make",        "form chrome new",
+            "form chrome open",        "form chrome start",
+            "form create browser",     "form create chrome",
+            "form create g suite",     "form create google",
+            "form create workspace",   "form g suite create",
+            "form g suite make",       "form g suite new",
+            "form g suite open",       "form g suite start",
+            "form google create",      "form google make",
+            "form google new",         "form google open",
+            "form google start",       "form make browser",
+            "form make chrome",        "form make g suite",
+            "form make google",        "form make workspace",
+            "form new browser",        "form new chrome",
+            "form new g suite",        "form new google",
+            "form new workspace",      "form open browser",
+            "form open chrome",        "form open g suite",
+            "form open google",        "form open workspace",
+            "form start browser",      "form start chrome",
+            "form start g suite",      "form start google",
+            "form start workspace",    "form workspace create",
+            "form workspace make",     "form workspace new",
+            "form workspace open",     "form workspace start",
+            "forms browser create",    "forms browser make",
+            "forms browser new",       "forms browser open",
+            "forms browser start",     "forms chrome create",
+            "forms chrome make",       "forms chrome new",
+            "forms chrome open",       "forms chrome start",
+            "forms create browser",    "forms create chrome",
+            "forms create g suite",    "forms create google",
+            "forms create workspace",  "forms g suite create",
+            "forms g suite make",      "forms g suite new",
+            "forms g suite open",      "forms g suite start",
+            "forms google create",     "forms google make",
+            "forms google new",        "forms google open",
+            "forms google start",      "forms make browser",
+            "forms make chrome",       "forms make g suite",
+            "forms make google",       "forms make workspace",
+            "forms new browser",       "forms new chrome",
+            "forms new g suite",       "forms new google",
+            "forms new workspace",     "forms open browser",
+            "forms open chrome",       "forms open g suite",
+            "forms open google",       "forms open workspace",
+            "forms start browser",     "forms start chrome",
+            "forms start g suite",     "forms start google",
+            "forms start workspace",   "forms workspace create",
+            "forms workspace make",    "forms workspace new",
+            "forms workspace open",    "forms workspace start",
+            "g suite create form",     "g suite create forms",
+            "g suite create quiz",     "g suite create survey",
+            "g suite form create",     "g suite form make",
+            "g suite form new",        "g suite form open",
+            "g suite form start",      "g suite forms create",
+            "g suite forms make",      "g suite forms new",
+            "g suite forms open",      "g suite forms start",
+            "g suite make form",       "g suite make forms",
+            "g suite make quiz",       "g suite make survey",
+            "g suite new form",        "g suite new forms",
+            "g suite new quiz",        "g suite new survey",
+            "g suite open form",       "g suite open forms",
+            "g suite open quiz",       "g suite open survey",
+            "g suite quiz create",     "g suite quiz make",
+            "g suite quiz new",        "g suite quiz open",
+            "g suite quiz start",      "g suite start form",
+            "g suite start forms",     "g suite start quiz",
+            "g suite start survey",    "g suite survey create",
+            "g suite survey make",     "g suite survey new",
+            "g suite survey open",     "g suite survey start",
+            "google create form",      "google create forms",
+            "google create quiz",      "google create survey",
+            "google form create",      "google form make",
+            "google form new",         "google form open",
+            "google form start",       "google forms create",
+            "google forms make",       "google forms new",
+            "google forms open",       "google forms start",
+            "google make form",        "google make forms",
+            "google make quiz",        "google make survey",
+            "google new form",         "google new forms",
+            "google new quiz",         "google new survey",
+            "google open form",        "google open forms",
+            "google open quiz",        "google open survey",
+            "google quiz create",      "google quiz make",
+            "google quiz new",         "google quiz open",
+            "google quiz start",       "google start form",
+            "google start forms",      "google start quiz",
+            "google start survey",     "google survey create",
+            "google survey make",      "google survey new",
+            "google survey open",      "google survey start",
+            "make browser form",       "make browser forms",
+            "make browser quiz",       "make browser survey",
+            "make chrome form",        "make chrome forms",
+            "make chrome quiz",        "make chrome survey",
+            "make form browser",       "make form chrome",
+            "make form g suite",       "make form google",
+            "make form workspace",     "make forms browser",
+            "make forms chrome",       "make forms g suite",
+            "make forms google",       "make forms workspace",
+            "make g suite form",       "make g suite forms",
+            "make g suite quiz",       "make g suite survey",
+            "make google form",        "make google forms",
+            "make google quiz",        "make google survey",
+            "make quiz browser",       "make quiz chrome",
+            "make quiz g suite",       "make quiz google",
+            "make quiz workspace",     "make survey browser",
+            "make survey chrome",      "make survey g suite",
+            "make survey google",      "make survey workspace",
+            "make workspace form",     "make workspace forms",
+            "make workspace quiz",     "make workspace survey",
+            "new browser form",        "new browser forms",
+            "new browser quiz",        "new browser survey",
+            "new chrome form",         "new chrome forms",
+            "new chrome quiz",         "new chrome survey",
+            "new form browser",        "new form chrome",
+            "new form g suite",        "new form google",
+            "new form workspace",      "new forms browser",
+            "new forms chrome",        "new forms g suite",
+            "new forms google",        "new forms workspace",
+            "new g suite form",        "new g suite forms",
+            "new g suite quiz",        "new g suite survey",
+            "new google form",         "new google forms",
+            "new google quiz",         "new google survey",
+            "new quiz browser",        "new quiz chrome",
+            "new quiz g suite",        "new quiz google",
+            "new quiz workspace",      "new survey browser",
+            "new survey chrome",       "new survey g suite",
+            "new survey google",       "new survey workspace",
+            "new workspace form",      "new workspace forms",
+            "new workspace quiz",      "new workspace survey",
+            "open browser form",       "open browser forms",
+            "open browser quiz",       "open browser survey",
+            "open chrome form",        "open chrome forms",
+            "open chrome quiz",        "open chrome survey",
+            "open form browser",       "open form chrome",
+            "open form g suite",       "open form google",
+            "open form workspace",     "open forms browser",
+            "open forms chrome",       "open forms g suite",
+            "open forms google",       "open forms workspace",
+            "open g suite form",       "open g suite forms",
+            "open g suite quiz",       "open g suite survey",
+            "open google form",        "open google forms",
+            "open google quiz",        "open google survey",
+            "open quiz browser",       "open quiz chrome",
+            "open quiz g suite",       "open quiz google",
+            "open quiz workspace",     "open survey browser",
+            "open survey chrome",      "open survey g suite",
+            "open survey google",      "open survey workspace",
+            "open workspace form",     "open workspace forms",
+            "open workspace quiz",     "open workspace survey",
+            "quiz browser create",     "quiz browser make",
+            "quiz browser new",        "quiz browser open",
+            "quiz browser start",      "quiz chrome create",
+            "quiz chrome make",        "quiz chrome new",
+            "quiz chrome open",        "quiz chrome start",
+            "quiz create browser",     "quiz create chrome",
+            "quiz create g suite",     "quiz create google",
+            "quiz create workspace",   "quiz g suite create",
+            "quiz g suite make",       "quiz g suite new",
+            "quiz g suite open",       "quiz g suite start",
+            "quiz google create",      "quiz google make",
+            "quiz google new",         "quiz google open",
+            "quiz google start",       "quiz make browser",
+            "quiz make chrome",        "quiz make g suite",
+            "quiz make google",        "quiz make workspace",
+            "quiz new browser",        "quiz new chrome",
+            "quiz new g suite",        "quiz new google",
+            "quiz new workspace",      "quiz open browser",
+            "quiz open chrome",        "quiz open g suite",
+            "quiz open google",        "quiz open workspace",
+            "quiz start browser",      "quiz start chrome",
+            "quiz start g suite",      "quiz start google",
+            "quiz start workspace",    "quiz workspace create",
+            "quiz workspace make",     "quiz workspace new",
+            "quiz workspace open",     "quiz workspace start",
+            "start browser form",      "start browser forms",
+            "start browser quiz",      "start browser survey",
+            "start chrome form",       "start chrome forms",
+            "start chrome quiz",       "start chrome survey",
+            "start form browser",      "start form chrome",
+            "start form g suite",      "start form google",
+            "start form workspace",    "start forms browser",
+            "start forms chrome",      "start forms g suite",
+            "start forms google",      "start forms workspace",
+            "start g suite form",      "start g suite forms",
+            "start g suite quiz",      "start g suite survey",
+            "start google form",       "start google forms",
+            "start google quiz",       "start google survey",
+            "start quiz browser",      "start quiz chrome",
+            "start quiz g suite",      "start quiz google",
+            "start quiz workspace",    "start survey browser",
+            "start survey chrome",     "start survey g suite",
+            "start survey google",     "start survey workspace",
+            "start workspace form",    "start workspace forms",
+            "start workspace quiz",    "start workspace survey",
+            "survey browser create",   "survey browser make",
+            "survey browser new",      "survey browser open",
+            "survey browser start",    "survey chrome create",
+            "survey chrome make",      "survey chrome new",
+            "survey chrome open",      "survey chrome start",
+            "survey create browser",   "survey create chrome",
+            "survey create g suite",   "survey create google",
+            "survey create workspace", "survey g suite create",
+            "survey g suite make",     "survey g suite new",
+            "survey g suite open",     "survey g suite start",
+            "survey google create",    "survey google make",
+            "survey google new",       "survey google open",
+            "survey google start",     "survey make browser",
+            "survey make chrome",      "survey make g suite",
+            "survey make google",      "survey make workspace",
+            "survey new browser",      "survey new chrome",
+            "survey new g suite",      "survey new google",
+            "survey new workspace",    "survey open browser",
+            "survey open chrome",      "survey open g suite",
+            "survey open google",      "survey open workspace",
+            "survey start browser",    "survey start chrome",
+            "survey start g suite",    "survey start google",
+            "survey start workspace",  "survey workspace create",
+            "survey workspace make",   "survey workspace new",
+            "survey workspace open",   "survey workspace start",
+            "workspace create form",   "workspace create forms",
+            "workspace create quiz",   "workspace create survey",
+            "workspace form create",   "workspace form make",
+            "workspace form new",      "workspace form open",
+            "workspace form start",    "workspace forms create",
+            "workspace forms make",    "workspace forms new",
+            "workspace forms open",    "workspace forms start",
+            "workspace make form",     "workspace make forms",
+            "workspace make quiz",     "workspace make survey",
+            "workspace new form",      "workspace new forms",
+            "workspace new quiz",      "workspace new survey",
+            "workspace open form",     "workspace open forms",
+            "workspace open quiz",     "workspace open survey",
+            "workspace quiz create",   "workspace quiz make",
+            "workspace quiz new",      "workspace quiz open",
+            "workspace quiz start",    "workspace start form",
+            "workspace start forms",   "workspace start quiz",
+            "workspace start survey",  "workspace survey create",
+            "workspace survey make",   "workspace survey new",
+            "workspace survey open",   "workspace survey start",
         },
 
         // ID#21
         {
-            // Generated suggestions:
             "browser chrome features",
             "browser chrome features explore",
             "browser chrome features learn",
@@ -15724,7 +15059,6 @@
 
         // ID#22
         {
-            // Generated suggestions:
             "adjust browser google account",
             "adjust chrome google account",
             "adjust google account",
@@ -15785,7 +15119,6 @@
 
         // ID#24
         {
-            // Generated suggestions:
             "browser change gmail account password",
             "browser change gmail password",
             "browser change google account password",
@@ -16110,7 +15443,6 @@
 
         // ID#27
         {
-            // Generated suggestions:
             "chrome dino",
             "chrome dino game",
             "chrome dinosaur",
@@ -16126,7 +15458,6 @@
 
         // ID#28
         {
-            // Generated suggestions:
             "device find",
             "device help find",
             "device help locate",
@@ -16203,7 +15534,6 @@
 
         // ID#29
         {
-            // Generated suggestions:
             "change google privacy",
             "change google privacy settings",
             "change my privacy on google",
@@ -16221,7 +15551,6 @@
 
         // ID#31
         {
-            // Generated suggestions:
             "alter browser settings",
             "alter chrome browser settings",
             "alter chrome settings",
@@ -16311,7 +15640,6 @@
 
         // ID#32
         {
-            // Generated suggestions:
             "alter browser downloads",
             "alter chrome browser downloads",
             "alter chrome downloads",
@@ -16416,7 +15744,6 @@
 
         // ID#33
         {
-            // Generated suggestions:
             "browser history find",
             "browser history revisit",
             "browser history see",
@@ -16505,7 +15832,6 @@
 
         // ID#36
         {
-            // Generated suggestions:
             "alter browser font",
             "alter browser font size",
             "alter browser font sizes",
@@ -17308,7 +16634,6 @@
 
         // ID#37
         {
-            // Generated suggestions:
             "change chrome appearance",
             "change chrome backgrounds",
             "change chrome color",
@@ -17404,7 +16729,6 @@
 
         // ID#38
         {
-            // Generated suggestions:
             "add browser custom search",
             "add browser custom search engines",
             "add browser customized search",
@@ -18582,9 +17906,6 @@
             "tab to search modify chrome",
             "tab to search modify google chrome",
         },
-
-        // End of generated test code
-        // clang-format on
     };
 
     // The test code below ensures that each element of the outer vector above,
diff --git a/chrome/browser/ui/omnibox/omnibox_pedals_unittest.cc b/chrome/browser/ui/omnibox/omnibox_pedals_unittest.cc
index 3d9996ce..a3232b6 100644
--- a/chrome/browser/ui/omnibox/omnibox_pedals_unittest.cc
+++ b/chrome/browser/ui/omnibox/omnibox_pedals_unittest.cc
@@ -16,97 +16,37 @@
 
 // Note: Pedals have their own components unit tests, which should be
 // the preferred place for testing the classes. The tests here are for
-// testing things that depend on Chrome resources, for example the localization
-// pak files generated by chrome:packed_resources.
+// testing things that depend on Chrome resources, for example GRIT strings.
 
 TEST(OmniboxPedals, DataLoadsForAllLocales) {
   // Locale selection is platform sensitive. On Linux, environment is used.
   std::unique_ptr<base::Environment> env = base::Environment::Create();
   MockAutocompleteProviderClient client;
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures({}, {});
 
-  // This used to have a vector of strings for specific trigger testing in each
-  // language but those depended on pedal_processor, which is deprecated, so
-  // for now they're removed. If l10n produces cases, we may reinstate them,
-  // so the structure is worth keeping, but for now we just use an exhaustive
-  // list of pedals-supported locales and ensure each loads below.
-  struct TestCase {
-    std::string locale;
+  // This is an exhaustive list of pedals-supported locales used to ensure
+  // translation data for each loads below.
+  const std::string locales[] = {
+      "am",    "ar",    "bg", "bn",     "ca", "cs",    "da",    "de",  "el",
+      "en",    "en-GB", "es", "es-419", "et", "fa",    "fi",    "fil", "fr",
+      "gu",    "he",    "hi", "hr",     "hu", "id",    "it",    "ja",  "kn",
+      "ko",    "lt",    "lv", "ml",     "mr", "ms",    "nl",    "pl",  "pt-BR",
+      "pt-PT", "ro",    "ru", "sk",     "sl", "sr",    "sv",    "sw",  "ta",
+      "te",    "th",    "tr", "uk",     "vi", "zh-CN", "zh-TW",
   };
-  const TestCase test_cases[] = {
-      // clang-format off
-      // Test cases generated by pedal_processor:
-      { "am", },
-      { "ar", },
-      { "bg", },
-      { "bn", },
-      { "ca", },
-      { "cs", },
-      { "da", },
-      { "de", },
-      { "el", },
-      { "en", },
-      { "en-GB", },
-      { "es", },
-      { "es-419", },
-      { "et", },
-      { "fa", },
-      { "fi", },
-      { "fil", },
-      { "fr", },
-      { "gu", },
-      { "he", },
-      { "hi", },
-      { "hr", },
-      { "hu", },
-      { "id", },
-      { "it", },
-      { "ja", },
-      { "kn", },
-      { "ko", },
-      { "lt", },
-      { "lv", },
-      { "ml", },
-      { "mr", },
-      { "ms", },
-      { "nl", },
-      { "pl", },
-      { "pt-BR", },
-      { "pt-PT", },
-      { "ro", },
-      { "ru", },
-      { "sk", },
-      { "sl", },
-      { "sr", },
-      { "sv", },
-      { "sw", },
-      { "ta", },
-      { "te", },
-      { "th", },
-      { "tr", },
-      { "uk", },
-      { "vi", },
-      { "zh-CN", },
-      { "zh-TW", },
-      // clang-format on
-  };
-  for (const TestCase& test_case : test_cases) {
+  for (const std::string& locale : locales) {
     // Prepare the shared ResourceBundle with data for tested locale.
-    env->SetVar("LANG", test_case.locale);
-    ui::ResourceBundle::GetSharedInstance().ReloadLocaleResources(
-        test_case.locale);
+    env->SetVar("LANG", locale);
+    ui::ResourceBundle::GetSharedInstance().ReloadLocaleResources(locale);
 
     // Instantiating the provider loads concept data from shared ResourceBundle,
     // or from omnibox_pedal_synonyms.grd if using translation console.
-    // Note, pedals initialization must happen after features are enabled above,
-    // so that the full set of pedals will be created and loaded.
+    // Note, with translation console process, we don't have specific cover
+    // cases to test, and there is no fallback to English. Just instantiating
+    // the provider above confirms that any available translation data loads
+    // because the `OmniboxPedalProvider` ctor loads, parses, transforms, and
+    // checks all trigger grit strings.
     client.set_pedal_provider(std::make_unique<OmniboxPedalProvider>(
         client, GetPedalImplementations(client.IsOffTheRecord(), true)));
     EXPECT_EQ(client.GetPedalProvider()->FindPedalMatch(u""), nullptr);
-
-    // Note, with translation console process, we don't have specific cover
-    // cases to test, and there is no fallback to English. Just instantiating
-    // the provider above confirms that any available translation data loads.
   }
 }
diff --git a/chrome/browser/ui/search_engines/search_engine_tab_helper.cc b/chrome/browser/ui/search_engines/search_engine_tab_helper.cc
index a943d51..8fd09ba 100644
--- a/chrome/browser/ui/search_engines/search_engine_tab_helper.cc
+++ b/chrome/browser/ui/search_engines/search_engine_tab_helper.cc
@@ -42,16 +42,20 @@
 
 // static
 void SearchEngineTabHelper::BindOpenSearchDescriptionDocumentHandler(
-    mojo::PendingAssociatedReceiver<
-        chrome::mojom::OpenSearchDescriptionDocumentHandler> receiver,
-    content::RenderFrameHost* rfh) {
+    content::RenderFrameHost* rfh,
+    mojo::PendingReceiver<chrome::mojom::OpenSearchDescriptionDocumentHandler>
+        receiver) {
+  // Bind only for outermost main frames.
+  if (rfh->GetParentOrOuterDocument())
+    return;
+
   auto* web_contents = content::WebContents::FromRenderFrameHost(rfh);
   if (!web_contents)
     return;
   auto* tab_helper = SearchEngineTabHelper::FromWebContents(web_contents);
   if (!tab_helper)
     return;
-  tab_helper->osdd_handler_receivers_.Bind(rfh, std::move(receiver));
+  tab_helper->osdd_handler_receivers_.Add(tab_helper, std::move(receiver));
 }
 
 SearchEngineTabHelper::~SearchEngineTabHelper() = default;
@@ -98,8 +102,7 @@
 
 SearchEngineTabHelper::SearchEngineTabHelper(WebContents* web_contents)
     : content::WebContentsObserver(web_contents),
-      content::WebContentsUserData<SearchEngineTabHelper>(*web_contents),
-      osdd_handler_receivers_(web_contents, this) {
+      content::WebContentsUserData<SearchEngineTabHelper>(*web_contents) {
   DCHECK(web_contents);
 
   favicon::CreateContentFaviconDriverForWebContents(web_contents);
@@ -114,11 +117,6 @@
   // necessary uses TemplateURLFetcher to download the OSDD and create a
   // keyword.
 
-  // Only accept messages from the main frame.
-  if (osdd_handler_receivers_.GetCurrentTargetFrame() !=
-      web_contents()->GetPrimaryMainFrame())
-    return;
-
   // Make sure that the page is the current page and other basic checks.
   // When |page_url| has file: scheme, this method doesn't work because of
   // http://b/issue?id=863583. For that reason, this doesn't check and allow
diff --git a/chrome/browser/ui/search_engines/search_engine_tab_helper.h b/chrome/browser/ui/search_engines/search_engine_tab_helper.h
index 19b1946..3fcb39e 100644
--- a/chrome/browser/ui/search_engines/search_engine_tab_helper.h
+++ b/chrome/browser/ui/search_engines/search_engine_tab_helper.h
@@ -11,13 +11,15 @@
 #include "components/favicon/core/favicon_driver.h"
 #include "components/favicon/core/favicon_driver_observer.h"
 #include "components/find_in_page/find_notification_details.h"
-#include "content/public/browser/render_frame_host_receiver_set.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
 
 namespace content {
 class NavigationEntry;
-}
+class RenderFrameHost;
+}  // namespace content
 
 // Per-tab search engine manager. Handles dealing search engine processing
 // functionality.
@@ -27,13 +29,19 @@
       public chrome::mojom::OpenSearchDescriptionDocumentHandler,
       public favicon::FaviconDriverObserver {
  public:
+  // Binds to the supplied receiver if `rfh` is the outermost frame in a
+  // WebContents. Each WebContents could have multiple outermost frames, e.g.
+  // the primary main frame, prerendering main frames, and main frames stored in
+  // the back-forward cache.
   static void BindOpenSearchDescriptionDocumentHandler(
-      mojo::PendingAssociatedReceiver<
-          chrome::mojom::OpenSearchDescriptionDocumentHandler> receiver,
-      content::RenderFrameHost* rfh);
+      content::RenderFrameHost* rfh,
+      mojo::PendingReceiver<chrome::mojom::OpenSearchDescriptionDocumentHandler>
+          receiver);
 
   SearchEngineTabHelper(const SearchEngineTabHelper&) = delete;
   SearchEngineTabHelper& operator=(const SearchEngineTabHelper&) = delete;
+  SearchEngineTabHelper(SearchEngineTabHelper&&) = delete;
+  SearchEngineTabHelper& operator=(SearchEngineTabHelper&&) = delete;
 
   ~SearchEngineTabHelper() override;
 
@@ -64,8 +72,7 @@
   // If params has a searchable form, this tries to create a new keyword.
   void GenerateKeywordIfNecessary(content::NavigationHandle* handle);
 
-  content::RenderFrameHostReceiverSet<
-      chrome::mojom::OpenSearchDescriptionDocumentHandler>
+  mojo::ReceiverSet<chrome::mojom::OpenSearchDescriptionDocumentHandler>
       osdd_handler_receivers_;
 
   base::ScopedObservation<favicon::FaviconDriver,
diff --git a/chrome/browser/ui/search_engines/search_engine_tab_helper_browsertest.cc b/chrome/browser/ui/search_engines/search_engine_tab_helper_browsertest.cc
index fcc3ada..2c6eaa97 100644
--- a/chrome/browser/ui/search_engines/search_engine_tab_helper_browsertest.cc
+++ b/chrome/browser/ui/search_engines/search_engine_tab_helper_browsertest.cc
@@ -251,3 +251,6 @@
   // A new template url is added on the primary page.
   EXPECT_NE(template_urls, url_service->GetTemplateURLs());
 }
+
+// TODO(http://crbug.com/1270519): Add a test for prerendering scenarios there
+// the OpenSearchDescriptionDocumentHandler mojo calls are deferred.
diff --git a/chrome/browser/ui/tabs/tab_group.cc b/chrome/browser/ui/tabs/tab_group.cc
index 5ccb6db..712ed2a6 100644
--- a/chrome/browser/ui/tabs/tab_group.cc
+++ b/chrome/browser/ui/tabs/tab_group.cc
@@ -141,13 +141,13 @@
 }
 
 void TabGroup::SaveGroup() {
-  std::vector<SavedTabGroupTab> urls;
+  std::vector<SavedTabGroupTab> tabs;
   const gfx::Range tab_range = ListTabs();
   const base::GUID saved_group_guid = base::GUID::GenerateRandomV4();
   for (auto i = tab_range.start(); i < tab_range.end(); ++i) {
     content::WebContents* web_contents = controller_->GetWebContentsAt(i);
     const GURL& url = web_contents->GetVisibleURL();
-    urls.emplace_back(
+    tabs.emplace_back(
         SavedTabGroupTab(url, saved_group_guid)
             .SetTitle(web_contents->GetTitle())
             .SetFavicon(favicon::TabFaviconFromWebContents(web_contents)));
@@ -155,8 +155,10 @@
 
   SavedTabGroupKeyedService* backend =
       SavedTabGroupServiceFactory::GetForProfile(controller_->GetProfile());
+  if (!backend || !backend->model())
+    return;
   SavedTabGroup saved_tab_group(visual_data_->title(), visual_data_->color(),
-                                urls, saved_group_guid, id_);
+                                tabs, saved_group_guid, id_);
   backend->model()->Add(saved_tab_group);
 }
 
@@ -165,5 +167,7 @@
 
   SavedTabGroupKeyedService* backend =
       SavedTabGroupServiceFactory::GetForProfile(controller_->GetProfile());
+  if (!backend || !backend->model())
+    return;
   backend->model()->Remove(id_);
 }
diff --git a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar_browsertest.cc b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar_browsertest.cc
index 006eeef4..2a0d482 100644
--- a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar_browsertest.cc
+++ b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar_browsertest.cc
@@ -47,9 +47,9 @@
 
     const SavedTabGroup* saved_tab_group = stg_model->Get(guid);
     EXPECT_NE(saved_tab_group, nullptr);
-    EXPECT_TRUE(saved_tab_group->tab_group_id().has_value());
+    EXPECT_TRUE(saved_tab_group->local_group_id().has_value());
     EXPECT_TRUE(model->group_model()->ContainsTabGroup(
-        saved_tab_group->tab_group_id().value()));
+        saved_tab_group->local_group_id().value()));
     EXPECT_NE(model->GetTabCount(), original_model_count);
   }
 
@@ -59,9 +59,9 @@
     chrome::OpenSavedTabGroup(browser(), guid, 1);
     const SavedTabGroup* saved_tab_group = stg_model->Get(guid);
     EXPECT_NE(saved_tab_group, nullptr);
-    EXPECT_TRUE(saved_tab_group->tab_group_id().has_value());
+    EXPECT_TRUE(saved_tab_group->local_group_id().has_value());
     EXPECT_TRUE(model->group_model()->ContainsTabGroup(
-        saved_tab_group->tab_group_id().value()));
+        saved_tab_group->local_group_id().value()));
     EXPECT_EQ(model->count(), original_model_count);
   }
 }
@@ -87,9 +87,9 @@
     const SavedTabGroup* saved_tab_group = stg_model->Get(guid);
 
     EXPECT_NE(saved_tab_group, nullptr);
-    EXPECT_TRUE(saved_tab_group->tab_group_id().has_value());
+    EXPECT_TRUE(saved_tab_group->local_group_id().has_value());
     EXPECT_TRUE(model->group_model()->ContainsTabGroup(
-        saved_tab_group->tab_group_id().value()));
+        saved_tab_group->local_group_id().value()));
     stg_model->Remove(saved_tab_group->saved_guid());
   }
 
diff --git a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_button.cc b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_button.cc
index 8f0a0fad..bcb94ae 100644
--- a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_button.cc
+++ b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_button.cc
@@ -51,7 +51,8 @@
     bool animations_enabled)
     : MenuButton(std::move(callback), group.title()),
       tab_group_color_id_(group.color()),
-      is_group_in_tabstrip_(group.tab_group_id().has_value()),
+      is_group_in_tabstrip_(group.local_group_id().has_value()),
+      guid_(group.saved_guid()),
       tabs_(group.saved_tabs()),
       page_navigator_callback_(std::move(page_navigator)),
       context_menu_controller_(
diff --git a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_button.h b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_button.h
index d19debd..81fe1e26 100644
--- a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_button.h
+++ b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_button.h
@@ -54,6 +54,8 @@
     return tab_group_color_id_;
   }
 
+  const base::GUID guid() { return guid_; }
+
  private:
   std::unique_ptr<ui::DialogModel> CreateDialogModelForContextMenu();
 
@@ -66,6 +68,9 @@
   // Denotes if the tabgroup is currently open in the tabstrip.
   bool is_group_in_tabstrip_;
 
+  // The guid used to identify the group this button represents.
+  base::GUID guid_;
+
   // The tabs to be displayed in the context menu. Currently supports tab title,
   // url, and favicon.
   const std::vector<SavedTabGroupTab> tabs_;
diff --git a/chrome/browser/ui/views/lens/lens_region_search_instructions_view.cc b/chrome/browser/ui/views/lens/lens_region_search_instructions_view.cc
index 7b27427..2982ca4 100644
--- a/chrome/browser/ui/views/lens/lens_region_search_instructions_view.cc
+++ b/chrome/browser/ui/views/lens/lens_region_search_instructions_view.cc
@@ -34,7 +34,6 @@
 constexpr int kCloseButtonSize = 17;
 constexpr int kCornerRadius = 18;
 constexpr int kLabelExtraLeftMargin = 2;
-constexpr int kSelectionIconTopMargin = 2;
 
 int GetLensInstructionChipString() {
   if (features::UseAltChipString()) {
@@ -127,15 +126,6 @@
             selection_icon, kColorFeatureLensPromoBubbleForeground,
             layout_provider->GetDistanceMetric(
                 DISTANCE_BUBBLE_HEADER_VECTOR_ICON_SIZE)));
-    // TODO(b/244610006): We need to set a top margin to make sure our icons
-    // feel properly centered even though they are vertically centered. Only
-    // needed for the selection icons which contain a cross cursor. Asset should
-    // be updated in the future to make this unnecessary.
-    selection_icon_view->SetProperty(
-        views::kMarginsKey,
-        gfx::Insets::TLBR(
-            features::UseSelectionIconWithImage() ? 0 : kSelectionIconTopMargin,
-            0, 0, 0));
     AddChildView(std::move(selection_icon_view));
   }
 
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
index c0e88a0..da20254 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
@@ -27,6 +27,7 @@
 #include "chrome/grit/generated_resources.h"
 #include "components/omnibox/browser/actions/omnibox_pedal.h"
 #include "components/omnibox/browser/autocomplete_match_type.h"
+#include "components/omnibox/browser/omnibox.mojom-shared.h"
 #include "components/omnibox/browser/omnibox_edit_model.h"
 #include "components/omnibox/browser/omnibox_popup_selection.h"
 #include "components/omnibox/browser/vector_icons.h"
@@ -422,8 +423,12 @@
 // OmniboxResultView, views::View overrides:
 
 bool OmniboxResultView::OnMousePressed(const ui::MouseEvent& event) {
-  if (event.IsOnlyLeftMouseButton())
+  if (event.IsOnlyLeftMouseButton()) {
     popup_contents_view_->SetSelectedIndex(model_index_);
+    // Inform the model that a new result is now selected via mouse press.
+    model_->OnNavigationLikely(model_index_,
+                               omnibox::mojom::NavigationPredictor::kMouseDown);
+  }
   return true;
 }
 
diff --git a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_browsertest.cc b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_browsertest.cc
index 79bc09b..15b719a 100644
--- a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_browsertest.cc
+++ b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_browsertest.cc
@@ -12,6 +12,7 @@
 #include "build/build_config.h"
 #include "chrome/browser/extensions/chrome_test_extension_loader.h"
 #include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/view_ids.h"
@@ -33,6 +34,7 @@
 #include "chrome/browser/ui/web_applications/app_browser_controller.h"
 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
 #include "chrome/browser/ui/web_applications/web_app_menu_model.h"
+#include "chrome/browser/web_applications/manifest_update_task.h"
 #include "chrome/browser/web_applications/user_display_mode.h"
 #include "chrome/browser/web_applications/web_app_constants.h"
 #include "chrome/browser/web_applications/web_app_install_info.h"
@@ -245,6 +247,11 @@
   const GURL app_url = https_server()->GetURL("/banners/theme-color.html");
   helper()->InstallAndLaunchWebApp(browser(), app_url);
 
+  // This is to ensure that for manifest updates, we auto
+  // accept the identity dialog and bypass the window closing requirement.
+  chrome::SetAutoAcceptAppIdentityUpdateForTesting(true);
+  web_app::ManifestUpdateTask::BypassWindowCloseWaitingForTesting() = true;
+
   content::WebContents* web_contents =
       helper()->app_browser()->tab_strip_model()->GetActiveWebContents();
   content::AwaitDocumentOnLoadCompleted(web_contents);
diff --git a/chrome/browser/ui/views/web_apps/web_app_tab_strip_browsertest.cc b/chrome/browser/ui/views/web_apps/web_app_tab_strip_browsertest.cc
index 7758eb11..c6f4d8c 100644
--- a/chrome/browser/ui/views/web_apps/web_app_tab_strip_browsertest.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_tab_strip_browsertest.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/ui/browser_command_controller.h"
 #include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
@@ -21,6 +22,7 @@
 #include "chrome/browser/ui/web_applications/app_browser_controller.h"
 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
 #include "chrome/browser/ui/web_applications/web_app_launch_utils.h"
+#include "chrome/browser/web_applications/manifest_update_task.h"
 #include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
 #include "chrome/browser/web_applications/user_display_mode.h"
 #include "chrome/browser/web_applications/web_app_command_scheduler.h"
@@ -82,6 +84,11 @@
     AppId app_id = test::InstallWebApp(profile, std::move(web_app_info));
 
     Browser* app_browser = LaunchWebAppBrowser(profile, app_id);
+
+    // This is to ensure that for manifest updates, we auto
+    // accept the identity dialog and bypass the window closing requirement.
+    chrome::SetAutoAcceptAppIdentityUpdateForTesting(true);
+    ManifestUpdateTask::BypassWindowCloseWaitingForTesting() = true;
     return App{app_id, app_browser,
                BrowserView::GetBrowserViewForBrowser(app_browser),
                app_browser->tab_strip_model()->GetActiveWebContents()};
diff --git a/chrome/browser/ui/web_applications/sub_apps_service_impl_browsertest.cc b/chrome/browser/ui/web_applications/sub_apps_service_impl_browsertest.cc
index c3570da..a3e9f570 100644
--- a/chrome/browser/ui/web_applications/sub_apps_service_impl_browsertest.cc
+++ b/chrome/browser/ui/web_applications/sub_apps_service_impl_browsertest.cc
@@ -13,9 +13,11 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/test/test_future.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/web_applications/web_app_controller_browsertest.h"
 #include "chrome/browser/web_applications/commands/sub_app_install_command.h"
+#include "chrome/browser/web_applications/manifest_update_task.h"
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/browser/web_applications/web_app_command_manager.h"
 #include "chrome/browser/web_applications/web_app_constants.h"
@@ -344,6 +346,11 @@
 
 // Verify that Add works if PWA is launched as standalone window.
 IN_PROC_BROWSER_TEST_F(SubAppsServiceImplBrowserTest, AddStandaloneWindow) {
+  // This is to ensure that for manifest updates, we auto
+  // accept the identity dialog and bypass the window closing requirement.
+  chrome::SetAutoAcceptAppIdentityUpdateForTesting(true);
+  ManifestUpdateTask::BypassWindowCloseWaitingForTesting() = true;
+
   NavigateToParentApp();
   InstallParentApp();
   content::WebContents* web_contents = OpenApplication(parent_app_id_);
@@ -848,6 +855,11 @@
 
 // Remove works with one app.
 IN_PROC_BROWSER_TEST_F(SubAppsServiceImplBrowserTest, RemoveOneApp) {
+  // This is to ensure that for manifest updates, we auto
+  // accept the identity dialog and bypass the window closing requirement.
+  chrome::SetAutoAcceptAppIdentityUpdateForTesting(true);
+  ManifestUpdateTask::BypassWindowCloseWaitingForTesting() = true;
+
   InstallParentApp();
   NavigateToParentApp();
   BindRemote();
@@ -882,6 +894,11 @@
 
 // Remove fails for a sub-app with a different parent_app_id.
 IN_PROC_BROWSER_TEST_F(SubAppsServiceImplBrowserTest, RemoveFailWrongParent) {
+  // This is to ensure that for manifest updates, we auto
+  // accept the identity dialog and bypass the window closing requirement.
+  chrome::SetAutoAcceptAppIdentityUpdateForTesting(true);
+  ManifestUpdateTask::BypassWindowCloseWaitingForTesting() = true;
+
   // SubApp plays the parent app here, SubApp2 is its sub-app, SubApp3 is the
   // other "parent app".
   AppId parent_app = InstallPWA(GetURL(kSubAppPath));
diff --git a/chrome/browser/ui/webui/app_home/app_home.mojom b/chrome/browser/ui/webui/app_home/app_home.mojom
index a86fdad5..90c5d70d 100644
--- a/chrome/browser/ui/webui/app_home/app_home.mojom
+++ b/chrome/browser/ui/webui/app_home/app_home.mojom
@@ -25,6 +25,8 @@
 interface PageHandler {
   // Get all apps' information that defined in `AppInfo`.
   GetApps() => (array<AppInfo> app_list);
+  // Uninstall app for specific `app_id`.
+  UninstallApp(string app_id);
 };
 
 // The `Page` interface is used for sending mojom action messsage
diff --git a/chrome/browser/ui/webui/app_home/app_home_page_handler.cc b/chrome/browser/ui/webui/app_home/app_home_page_handler.cc
index 2703b79b..0909b56 100644
--- a/chrome/browser/ui/webui/app_home/app_home_page_handler.cc
+++ b/chrome/browser/ui/webui/app_home/app_home_page_handler.cc
@@ -4,15 +4,22 @@
 #include "chrome/browser/ui/webui/app_home/app_home_page_handler.h"
 
 #include "chrome/browser/apps/app_service/app_icon/app_icon_source.h"
+#include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_ui_util.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/web_applications/web_app_dialog_manager.h"
+#include "chrome/browser/ui/web_applications/web_app_ui_manager_impl.h"
 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/browser/web_applications/web_app_registrar.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
+#include "components/webapps/browser/uninstall_result_code.h"
 #include "content/public/browser/web_ui.h"
 #include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_system.h"
 #include "url/gurl.h"
 
 using content::WebUI;
@@ -43,13 +50,23 @@
       profile_(profile),
       receiver_(this, std::move(receiver)),
       page_(std::move(page)),
-      web_app_provider_(web_app::WebAppProvider::GetForWebApps(profile)) {
+      web_app_provider_(web_app::WebAppProvider::GetForWebApps(profile)),
+      extension_service_(
+          extensions::ExtensionSystem::Get(profile)->extension_service()) {
   install_manager_observation_.Observe(&web_app_provider_->install_manager());
   ExtensionRegistry::Get(profile)->AddObserver(this);
 }
 
 AppHomePageHandler::~AppHomePageHandler() {
   ExtensionRegistry::Get(profile_)->RemoveObserver(this);
+  // Destroy `extension_uninstall_dialog_` now, since `this` is an
+  // `ExtensionUninstallDialog::Delegate` and the dialog may call back into
+  // `this` when destroyed.
+  extension_uninstall_dialog_.reset();
+}
+
+Browser* AppHomePageHandler::GetCurrentBrowser() {
+  return chrome::FindBrowserWithWebContents(web_ui_->GetWebContents());
 }
 
 app_home::mojom::AppInfoPtr AppHomePageHandler::CreateAppInfoPtrFromWebApp(
@@ -115,6 +132,76 @@
   }
 }
 
+void AppHomePageHandler::OnExtensionUninstallDialogClosed(
+    bool did_start_uninstall,
+    const std::u16string& error) {
+  CleanupAfterUninstall();
+}
+
+void AppHomePageHandler::CleanupAfterUninstall() {
+  uninstall_dialog_prompting_ = false;
+}
+
+void AppHomePageHandler::UninstallWebApp(const std::string& web_app_id) {
+  if (!web_app_provider_->install_finalizer().CanUserUninstallWebApp(
+          web_app_id)) {
+    LOG(ERROR) << "Attempt to uninstall a webapp that is non-usermanagable "
+                  "was made. App id : "
+               << web_app_id;
+    return;
+  }
+
+  uninstall_dialog_prompting_ = true;
+
+  auto uninstall_success_callback = base::BindOnce(
+      [](base::WeakPtr<AppHomePageHandler> app_home_page_handler,
+         webapps::UninstallResultCode code) {
+        if (app_home_page_handler) {
+          app_home_page_handler->CleanupAfterUninstall();
+        }
+      },
+      weak_ptr_factory_.GetWeakPtr());
+
+  Browser* browser = GetCurrentBrowser();
+  web_app::WebAppUiManagerImpl::Get(web_app_provider_)
+      ->dialog_manager()
+      .UninstallWebApp(web_app_id, webapps::WebappUninstallSource::kAppsPage,
+                       browser->window(),
+                       std::move(uninstall_success_callback));
+  return;
+}
+
+extensions::ExtensionUninstallDialog*
+AppHomePageHandler::CreateExtensionUninstallDialog() {
+  Browser* browser = GetCurrentBrowser();
+  extension_uninstall_dialog_ = extensions::ExtensionUninstallDialog::Create(
+      extension_service_->profile(), browser->window()->GetNativeWindow(),
+      this);
+  return extension_uninstall_dialog_.get();
+}
+
+void AppHomePageHandler::UninstallExtensionApp(const Extension* extension) {
+  if (!extensions::ExtensionSystem::Get(extension_service_->profile())
+           ->management_policy()
+           ->UserMayModifySettings(extension, nullptr)) {
+    LOG(ERROR) << "Attempt to uninstall an extension that is non-usermanagable "
+                  "was made. Extension id : "
+               << extension->id();
+    return;
+  }
+
+  uninstall_dialog_prompting_ = true;
+
+  Browser* browser = GetCurrentBrowser();
+  extension_uninstall_dialog_ = extensions::ExtensionUninstallDialog::Create(
+      extension_service_->profile(), browser->window()->GetNativeWindow(),
+      this);
+
+  extension_uninstall_dialog_->ConfirmUninstall(
+      extension, extensions::UNINSTALL_REASON_USER_INITIATED,
+      extensions::UNINSTALL_SOURCE_CHROME_APPS_PAGE);
+}
+
 void AppHomePageHandler::GetApps(GetAppsCallback callback) {
   std::vector<app_home::mojom::AppInfoPtr> result;
   FillWebAppInfoList(&result);
@@ -152,4 +239,22 @@
   page_->RemoveApp(std::move(app_info));
 }
 
+void AppHomePageHandler::UninstallApp(const std::string& app_id) {
+  if (uninstall_dialog_prompting_)
+    return;
+
+  if (web_app_provider_->registrar().IsInstalled(app_id) &&
+      !IsYoutubeExtension(app_id)) {
+    UninstallWebApp(app_id);
+    return;
+  }
+
+  const Extension* extension =
+      ExtensionRegistry::Get(extension_service_->profile())
+          ->GetInstalledExtension(app_id);
+  if (extension) {
+    UninstallExtensionApp(extension);
+  }
+}
+
 }  // namespace webapps
diff --git a/chrome/browser/ui/webui/app_home/app_home_page_handler.h b/chrome/browser/ui/webui/app_home/app_home_page_handler.h
index a63683a50..13f11f21 100644
--- a/chrome/browser/ui/webui/app_home/app_home_page_handler.h
+++ b/chrome/browser/ui/webui/app_home/app_home_page_handler.h
@@ -6,7 +6,9 @@
 #define CHROME_BROWSER_UI_WEBUI_APP_HOME_APP_HOME_PAGE_HANDLER_H_
 
 #include "base/memory/raw_ptr.h"
+#include "chrome/browser/extensions/extension_uninstall_dialog.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/webui/app_home/app_home.mojom.h"
 #include "chrome/browser/web_applications/web_app_id.h"
 #include "chrome/browser/web_applications/web_app_install_manager.h"
@@ -21,6 +23,8 @@
 
 namespace extensions {
 class Extension;
+class ExtensionService;
+class ExtensionUninstallDialog;
 }  // namespace extensions
 
 namespace web_app {
@@ -29,9 +33,11 @@
 
 namespace webapps {
 
-class AppHomePageHandler : public app_home::mojom::PageHandler,
-                           public web_app::WebAppInstallManagerObserver,
-                           public extensions::ExtensionRegistryObserver {
+class AppHomePageHandler
+    : public app_home::mojom::PageHandler,
+      public web_app::WebAppInstallManagerObserver,
+      public extensions::ExtensionRegistryObserver,
+      public extensions::ExtensionUninstallDialog::Delegate {
  public:
   AppHomePageHandler(
       content::WebUI*,
@@ -58,8 +64,24 @@
 
   // app_home::mojom::PageHandler:
   void GetApps(GetAppsCallback callback) override;
+  void UninstallApp(const std::string& app_id) override;
 
  private:
+  Browser* GetCurrentBrowser();
+
+  // Returns the ExtensionUninstallDialog object for this class, creating it if
+  // needed.
+  extensions::ExtensionUninstallDialog* CreateExtensionUninstallDialog();
+
+  // Reset some instance flags we use to track the currently uninstalling app.
+  void CleanupAfterUninstall();
+
+  // ExtensionUninstallDialog::Delegate:
+  void OnExtensionUninstallDialogClosed(bool did_start_uninstall,
+                                        const std::u16string& error) override;
+
+  void UninstallWebApp(const std::string& web_app_id);
+  void UninstallExtensionApp(const extensions::Extension* extension);
   void FillWebAppInfoList(std::vector<app_home::mojom::AppInfoPtr>* result);
   void FillExtensionInfoList(std::vector<app_home::mojom::AppInfoPtr>* result);
   app_home::mojom::AppInfoPtr CreateAppInfoPtrFromWebApp(
@@ -75,14 +97,23 @@
 
   mojo::Remote<app_home::mojom::Page> page_;
 
-  // The apps are represented in the web apps model, which outlives us since
-  // it's owned by our containing profile.
+  // The apps are represented in the web apps model, which outlives this class
+  // since it's owned by |profile_|.
   const raw_ptr<web_app::WebAppProvider> web_app_provider_;
 
+  // The apps are represented in the extensions model, which
+  // outlives this class since it's owned by |profile_|.
+  const raw_ptr<extensions::ExtensionService> extension_service_;
+
   base::ScopedObservation<web_app::WebAppInstallManager,
                           web_app::WebAppInstallManagerObserver>
       install_manager_observation_{this};
 
+  std::unique_ptr<extensions::ExtensionUninstallDialog>
+      extension_uninstall_dialog_;
+
+  bool uninstall_dialog_prompting_ = false;
+
   // Used for passing callbacks.
   base::WeakPtrFactory<AppHomePageHandler> weak_ptr_factory_{this};
 };
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler_browsertest.cc b/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler_browsertest.cc
index 6c655fa3..fefc1199 100644
--- a/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler_browsertest.cc
+++ b/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler_browsertest.cc
@@ -121,7 +121,7 @@
         observed_relative_drive_path(),
         "application/"
         "vnd.openxmlformats-officedocument.wordprocessingml.document",
-        test_file_name_, false, false, {}, {}, "abc123",
+        test_file_name_, false, false, false, {}, {}, "abc123",
         /*alternate_url=*/
         "https://docs.google.com/document/d/"
         "smalldocxid?rtpof=true&usp=drive_fs");
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/OWNERS b/chrome/browser/ui/webui/ash/in_session_password_change/OWNERS
similarity index 100%
rename from chrome/browser/ui/webui/chromeos/in_session_password_change/OWNERS
rename to chrome/browser/ui/webui/ash/in_session_password_change/OWNERS
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/base_lock_dialog.cc b/chrome/browser/ui/webui/ash/in_session_password_change/base_lock_dialog.cc
similarity index 89%
rename from chrome/browser/ui/webui/chromeos/in_session_password_change/base_lock_dialog.cc
rename to chrome/browser/ui/webui/ash/in_session_password_change/base_lock_dialog.cc
index 682acbb..193af47 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/base_lock_dialog.cc
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/base_lock_dialog.cc
@@ -2,13 +2,13 @@
 // 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/chromeos/in_session_password_change/base_lock_dialog.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/base_lock_dialog.h"
 
 #include "chrome/common/webui_url_constants.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 
@@ -43,4 +43,4 @@
   return ui::ModalType::MODAL_TYPE_SYSTEM;
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/base_lock_dialog.h b/chrome/browser/ui/webui/ash/in_session_password_change/base_lock_dialog.h
similarity index 73%
rename from chrome/browser/ui/webui/chromeos/in_session_password_change/base_lock_dialog.h
rename to chrome/browser/ui/webui/ash/in_session_password_change/base_lock_dialog.h
index 4a9f2703..852fabfb 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/base_lock_dialog.h
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/base_lock_dialog.h
@@ -2,12 +2,12 @@
 // 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_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_BASE_LOCK_DIALOG_H_
-#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_BASE_LOCK_DIALOG_H_
+#ifndef CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_BASE_LOCK_DIALOG_H_
+#define CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_BASE_LOCK_DIALOG_H_
 
 #include "chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h"
 
-namespace chromeos {
+namespace ash {
 
 // A modal system dialog without any frame decorating it.
 class BaseLockDialog : public SystemWebDialogDelegate {
@@ -28,6 +28,6 @@
   gfx::Size desired_size_;
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
-#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_BASE_LOCK_DIALOG_H_
+#endif  // CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_BASE_LOCK_DIALOG_H_
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/confirm_password_change_handler.cc b/chrome/browser/ui/webui/ash/in_session_password_change/confirm_password_change_handler.cc
similarity index 95%
rename from chrome/browser/ui/webui/chromeos/in_session_password_change/confirm_password_change_handler.cc
rename to chrome/browser/ui/webui/ash/in_session_password_change/confirm_password_change_handler.cc
index 8e7d2a6..bd8fff7 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/confirm_password_change_handler.cc
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/confirm_password_change_handler.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/browser/ui/webui/chromeos/in_session_password_change/confirm_password_change_handler.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/confirm_password_change_handler.h"
 
 #include <string>
 
@@ -15,7 +15,7 @@
 #include "components/prefs/pref_service.h"
 #include "components/user_manager/user_manager.h"
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 
@@ -102,4 +102,4 @@
                           weak_factory_.GetWeakPtr()));
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/confirm_password_change_handler.h b/chrome/browser/ui/webui/ash/in_session_password_change/confirm_password_change_handler.h
similarity index 82%
rename from chrome/browser/ui/webui/chromeos/in_session_password_change/confirm_password_change_handler.h
rename to chrome/browser/ui/webui/ash/in_session_password_change/confirm_password_change_handler.h
index 871dd20..1e8fd938 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/confirm_password_change_handler.h
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/confirm_password_change_handler.h
@@ -2,15 +2,15 @@
 // 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_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_CONFIRM_PASSWORD_CHANGE_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_CONFIRM_PASSWORD_CHANGE_HANDLER_H_
+#ifndef CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_CONFIRM_PASSWORD_CHANGE_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_CONFIRM_PASSWORD_CHANGE_HANDLER_H_
 
 #include "base/memory/weak_ptr.h"
 #include "base/values.h"
 #include "chrome/browser/ash/login/saml/in_session_password_change_manager.h"
 #include "content/public/browser/web_ui_message_handler.h"
 
-namespace chromeos {
+namespace ash {
 
 class ConfirmPasswordChangeHandler
     : public content::WebUIMessageHandler,
@@ -47,6 +47,6 @@
   base::WeakPtrFactory<ConfirmPasswordChangeHandler> weak_factory_{this};
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
-#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_CONFIRM_PASSWORD_CHANGE_HANDLER_H_
+#endif  // CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_CONFIRM_PASSWORD_CHANGE_HANDLER_H_
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_captive_portal_dialog.cc b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_captive_portal_dialog.cc
similarity index 92%
rename from chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_captive_portal_dialog.cc
rename to chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_captive_portal_dialog.cc
index c823e169..1cbc77fc2 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_captive_portal_dialog.cc
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_captive_portal_dialog.cc
@@ -2,15 +2,15 @@
 // 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/chromeos/in_session_password_change/lock_screen_captive_portal_dialog.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_captive_portal_dialog.h"
 
 #include "ash/constants/ash_features.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_reauth_dialogs.h"
 #include "chromeos/ash/components/network/network_connection_handler.h"
 #include "components/captive_portal/core/captive_portal_detector.h"
 
-namespace chromeos {
+namespace ash {
 
 LockScreenCaptivePortalDialog::LockScreenCaptivePortalDialog()
     : BaseLockDialog(
@@ -94,4 +94,4 @@
   params->type = views::Widget::InitParams::TYPE_WINDOW;
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_captive_portal_dialog.h b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_captive_portal_dialog.h
similarity index 70%
rename from chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_captive_portal_dialog.h
rename to chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_captive_portal_dialog.h
index db62dab..4cae7044 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_captive_portal_dialog.h
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_captive_portal_dialog.h
@@ -2,19 +2,19 @@
 // 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_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_CAPTIVE_PORTAL_DIALOG_H_
-#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_CAPTIVE_PORTAL_DIALOG_H_
+#ifndef CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_CAPTIVE_PORTAL_DIALOG_H_
+#define CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_CAPTIVE_PORTAL_DIALOG_H_
 
 #include <string>
 
 #include "base/callback.h"
 #include "base/callback_forward.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/base_lock_dialog.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/base_lock_dialog.h"
 #include "ui/views/widget/widget.h"
 
 class Profile;
 
-namespace chromeos {
+namespace ash {
 
 class LockScreenCaptivePortalDialog : public BaseLockDialog {
  public:
@@ -40,6 +40,6 @@
   void AdjustWidgetInitParams(views::Widget::InitParams* params) override;
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
-#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_CAPTIVE_PORTAL_DIALOG_H_
+#endif  // CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_CAPTIVE_PORTAL_DIALOG_H_
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_dialog.cc b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_dialog.cc
similarity index 87%
rename from chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_dialog.cc
rename to chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_dialog.cc
index 025db6c..1ae2c19 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_dialog.cc
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_dialog.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/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_dialog.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_dialog.h"
 
 #include <memory>
 
@@ -13,7 +13,7 @@
 #include "chrome/browser/ash/login/saml/in_session_password_sync_manager_factory.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_reauth_dialogs.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/browser_resources.h"
 #include "chrome/grit/generated_resources.h"
@@ -22,7 +22,7 @@
 #include "content/public/browser/web_ui_data_source.h"
 #include "ui/strings/grit/ui_strings.h"
 
-namespace chromeos {
+namespace ash {
 
 LockScreenNetworkDialog::LockScreenNetworkDialog(
     NetworkDialogCleanupCallback callback)
@@ -50,4 +50,4 @@
   Close();
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_dialog.h b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_dialog.h
similarity index 63%
rename from chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_dialog.h
rename to chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_dialog.h
index 3e730da3..1c7623e78 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_dialog.h
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_dialog.h
@@ -2,15 +2,15 @@
 // 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_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_NETWORK_DIALOG_H_
-#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_NETWORK_DIALOG_H_
+#ifndef CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_NETWORK_DIALOG_H_
+#define CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_NETWORK_DIALOG_H_
 
 #include "base/callback_forward.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/base_lock_dialog.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/base_lock_dialog.h"
 
 class Profile;
 
-namespace chromeos {
+namespace ash {
 
 class LockScreenNetworkDialog : public BaseLockDialog {
  public:
@@ -29,6 +29,6 @@
   NetworkDialogCleanupCallback callback_;
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
-#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_NETWORK_DIALOG_H_
+#endif  // CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_NETWORK_DIALOG_H_
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_handler.cc b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_handler.cc
similarity index 95%
rename from chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_handler.cc
rename to chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_handler.cc
index c9c1212..b5dd5b2 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_handler.cc
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_handler.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/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_handler.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_handler.h"
 
 #include <memory>
 #include <string>
@@ -33,7 +33,7 @@
 #include "ui/chromeos/devicetype_utils.h"
 #include "ui/chromeos/strings/network_element_localized_strings_provider.h"
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 
@@ -46,7 +46,7 @@
 InSessionPasswordSyncManager* GetInSessionPasswordSyncManager() {
   const user_manager::User* user =
       user_manager::UserManager::Get()->GetActiveUser();
-  Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+  Profile* profile = ProfileHelper::Get()->GetProfileByUser(user);
 
   return InSessionPasswordSyncManagerFactory::GetForProfile(profile);
 }
@@ -128,4 +128,4 @@
   ResolveJavascriptCallback(base::Value(callback_id), response);
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_handler.h b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_handler.h
similarity index 70%
rename from chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_handler.h
rename to chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_handler.h
index bf7bfe8..06c4bc8 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_handler.h
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_handler.h
@@ -2,18 +2,18 @@
 // 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_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_NETWORK_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_NETWORK_HANDLER_H_
+#ifndef CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_NETWORK_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_NETWORK_HANDLER_H_
 
 #include "base/memory/weak_ptr.h"
 #include "base/values.h"
 #include "content/public/browser/web_ui_message_handler.h"
 
-namespace chromeos {
+namespace ash {
 
 class NetworkConfigMessageHandler : public content::WebUIMessageHandler {
  public:
-  explicit NetworkConfigMessageHandler();
+  NetworkConfigMessageHandler();
   ~NetworkConfigMessageHandler() override;
 
   // WebUIMessageHandler implementation.
@@ -30,6 +30,6 @@
   base::WeakPtrFactory<NetworkConfigMessageHandler> weak_ptr_factory_{this};
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
-#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_NETWORK_HANDLER_H_
+#endif  // CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_NETWORK_HANDLER_H_
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_ui.cc b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_ui.cc
similarity index 89%
rename from chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_ui.cc
rename to chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_ui.cc
index 75d0269..8ddfcb0a 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_ui.cc
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_ui.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/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_ui.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_ui.h"
 
 #include <memory>
 #include <string>
@@ -16,7 +16,7 @@
 #include "chrome/browser/ash/login/saml/in_session_password_sync_manager_factory.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/extensions/tab_helper.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_handler.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_handler.h"
 #include "chrome/browser/ui/webui/chromeos/internet_config_dialog.h"
 #include "chrome/browser/ui/webui/chromeos/internet_detail_dialog.h"
 #include "chrome/common/url_constants.h"
@@ -36,7 +36,7 @@
 #include "ui/chromeos/devicetype_utils.h"
 #include "ui/chromeos/strings/network_element_localized_strings_provider.h"
 
-namespace chromeos {
+namespace ash {
 
 // static
 base::Value::Dict LockScreenNetworkUI::GetLocalizedStrings() {
@@ -87,10 +87,11 @@
 LockScreenNetworkUI::~LockScreenNetworkUI() = default;
 
 void LockScreenNetworkUI::BindInterface(
-    mojo::PendingReceiver<network_config::mojom::CrosNetworkConfig> receiver) {
-  ash::GetNetworkConfigService(std::move(receiver));
+    mojo::PendingReceiver<chromeos::network_config::mojom::CrosNetworkConfig>
+        receiver) {
+  GetNetworkConfigService(std::move(receiver));
 }
 
 WEB_UI_CONTROLLER_TYPE_IMPL(LockScreenNetworkUI)
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_ui.h b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_ui.h
similarity index 67%
rename from chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_ui.h
rename to chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_ui.h
index 919e58e8..f369d394 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_ui.h
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_ui.h
@@ -2,18 +2,17 @@
 // 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_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_NETWORK_UI_H_
-#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_NETWORK_UI_H_
+#ifndef CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_NETWORK_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_NETWORK_UI_H_
 
 #include "base/values.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_handler.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_handler.h"
 #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom-forward.h"
-
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "ui/web_dialogs/web_dialog_ui.h"
 #include "ui/webui/mojo_web_ui_controller.h"
 
-namespace chromeos {
+namespace ash {
 
 // WebUI controller for chrome://lock-network dialog.
 class LockScreenNetworkUI : public ui::MojoWebDialogUI {
@@ -26,7 +25,8 @@
   // Instantiates implementation of the mojom::CrosNetworkConfig mojo interface
   // passing the pending receiver that will be internally bound.
   void BindInterface(
-      mojo::PendingReceiver<network_config::mojom::CrosNetworkConfig> receiver);
+      mojo::PendingReceiver<chromeos::network_config::mojom::CrosNetworkConfig>
+          receiver);
 
   NetworkConfigMessageHandler* GetMainHandlerForTests() {
     return main_handler_;
@@ -39,6 +39,6 @@
   WEB_UI_CONTROLLER_TYPE_DECL();
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
-#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_NETWORK_UI_H_
+#endif  // CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_NETWORK_UI_H_
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.cc b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_reauth_dialogs.cc
similarity index 93%
rename from chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.cc
rename to chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_reauth_dialogs.cc
index c7dd958..02e7b2b 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.cc
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_reauth_dialogs.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/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_reauth_dialogs.h"
 
 #include <memory>
 #include <string>
@@ -22,12 +22,12 @@
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/base_lock_dialog.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/confirm_password_change_handler.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_captive_portal_dialog.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_dialog.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_start_reauth_ui.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/base_lock_dialog.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/confirm_password_change_handler.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_captive_portal_dialog.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_dialog.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_reauth_handler.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_start_reauth_ui.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/browser_resources.h"
 #include "chrome/grit/generated_resources.h"
@@ -42,7 +42,7 @@
 #include "ui/aura/window.h"
 #include "ui/strings/grit/ui_strings.h"
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 LockScreenStartReauthDialog* g_dialog = nullptr;
@@ -50,7 +50,7 @@
 InSessionPasswordSyncManager* GetInSessionPasswordSyncManager() {
   const user_manager::User* user =
       user_manager::UserManager::Get()->GetActiveUser();
-  Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+  Profile* profile = ProfileHelper::Get()->GetProfileByUser(user);
 
   return InSessionPasswordSyncManagerFactory::GetForProfile(profile);
 }
@@ -237,7 +237,7 @@
   DCHECK(profile_);
   is_network_dialog_visible_ = true;
   lock_screen_network_dialog_ =
-      std::make_unique<chromeos::LockScreenNetworkDialog>(base::BindOnce(
+      std::make_unique<LockScreenNetworkDialog>(base::BindOnce(
           &LockScreenStartReauthDialog::DeleteLockScreenNetworkDialog,
           base::Unretained(this)));
   lock_screen_network_dialog_->Show(profile_);
@@ -380,7 +380,7 @@
     // proxy credentials between different unlock attempts.
     webview_storage_partition->GetNetworkContext()
         ->SaveHttpAuthCacheProxyEntries(
-            base::BindOnce(&ash::TransferHttpAuthCacheToSystemNetworkContext,
+            base::BindOnce(&TransferHttpAuthCacheToSystemNetworkContext,
                            base::DoNothing()));
 
     const user_manager::User* user =
@@ -388,7 +388,7 @@
     Profile* profile = ProfileHelper::Get()->GetProfileByUser(user);
     // Transfer auth cache to the active user's profile so that there is no need
     // to enter them again after unlocking the device.
-    ash::ProfileAuthData::TransferHttpAuthCacheProxyEntries(
+    ProfileAuthData::TransferHttpAuthCacheProxyEntries(
         base::DoNothing(), webview_storage_partition,
         profile->GetDefaultStoragePartition());
   }
@@ -420,13 +420,13 @@
           FROM_HERE,
           base::BindOnce(&LockScreenStartReauthDialog::ReenableNetworkUpdates,
                          weak_factory_.GetWeakPtr()),
-          ash::kProxyAuthTimeout);
+          kProxyAuthTimeout);
 
       base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
           FROM_HERE,
           base::BindOnce(&LockScreenStartReauthDialog::TransferHttpAuthCaches,
                          weak_factory_.GetWeakPtr()),
-          ash::kAuthCacheTransferDelayMs);
+          kAuthCacheTransferDelayMs);
       g_dialog->Focus();
       break;
     }
@@ -453,4 +453,4 @@
   is_proxy_auth_in_progress_ = false;
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.h b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_reauth_dialogs.h
similarity index 89%
rename from chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.h
rename to chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_reauth_dialogs.h
index 4faf8a0c..8806ca0 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.h
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_reauth_dialogs.h
@@ -2,15 +2,15 @@
 // 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_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_REAUTH_DIALOGS_H_
-#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_REAUTH_DIALOGS_H_
+#ifndef CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_REAUTH_DIALOGS_H_
+#define CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_REAUTH_DIALOGS_H_
 
 #include "base/observer_list.h"
 #include "base/scoped_observation.h"
 #include "chrome/browser/ash/login/helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/base_lock_dialog.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/base_lock_dialog.h"
 #include "chrome/browser/ui/webui/chromeos/login/network_state_informer.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
 #include "chromeos/ash/components/network/network_state_handler_observer.h"
@@ -19,7 +19,7 @@
 #include "content/public/browser/notification_registrar.h"
 #include "ui/web_dialogs/web_dialog_ui.h"
 
-namespace chromeos {
+namespace ash {
 
 class LockScreenCaptivePortalDialog;
 class LockScreenNetworkDialog;
@@ -141,12 +141,6 @@
   base::WeakPtrFactory<LockScreenStartReauthDialog> weak_factory_{this};
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove after the //chrome/browser/chromeos
-// source migration is finished.
-namespace ash {
-using ::chromeos::LockScreenStartReauthDialog;
-}
-
-#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_REAUTH_DIALOGS_H_
+#endif  // CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_REAUTH_DIALOGS_H_
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.cc b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_reauth_handler.cc
similarity index 96%
rename from chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.cc
rename to chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_reauth_handler.cc
index cd5ba4c..94df3bde1 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.cc
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_reauth_handler.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/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_reauth_handler.h"
 
 #include <memory>
 
@@ -37,7 +37,7 @@
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
 
-namespace chromeos {
+namespace ash {
 namespace {
 
 bool ShouldDoSamlRedirect(const std::string& email) {
@@ -58,7 +58,7 @@
 Profile* GetActiveUserProfile() {
   const user_manager::User* user =
       user_manager::UserManager::Get()->GetActiveUser();
-  Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+  Profile* profile = ProfileHelper::Get()->GetProfileByUser(user);
   return profile;
 }
 
@@ -214,10 +214,10 @@
   params.SetBoolKey("readOnlyEmail", true);
   PrefService* local_state = g_browser_process->local_state();
   if (local_state->IsManagedPreference(
-          ash::prefs::kUrlParameterToAutofillSAMLUsername)) {
+          prefs::kUrlParameterToAutofillSAMLUsername)) {
     params.SetStringKey("urlParameterToAutofillSAMLUsername",
                         local_state->GetString(
-                            ash::prefs::kUrlParameterToAutofillSAMLUsername));
+                            prefs::kUrlParameterToAutofillSAMLUsername));
   }
 
   CallJavascript("loadAuthenticator", params);
@@ -317,8 +317,8 @@
 
 void LockScreenReauthHandler::CheckCredentials(
     std::unique_ptr<UserContext> user_context) {
-  Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByAccountId(
-      user_context->GetAccountId());
+  Profile* profile =
+      ProfileHelper::Get()->GetProfileByAccountId(user_context->GetAccountId());
   if (!profile) {
     LOG(ERROR) << "Invalid account id";
     return;
@@ -386,7 +386,7 @@
 
   // TODO(https://crbug.com/1295294) Eliminate redundant cryptohome check.
   check_passwords_against_cryptohome_helper_ =
-      std::make_unique<ash::CheckPasswordsAgainstCryptohomeHelper>(
+      std::make_unique<CheckPasswordsAgainstCryptohomeHelper>(
           *user_context_.get(), scraped_saml_passwords_,
           base::BindOnce(
               &LockScreenReauthHandler::ShowSamlConfirmPasswordScreen,
@@ -455,4 +455,4 @@
   return false;
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.h b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_reauth_handler.h
similarity index 87%
rename from chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.h
rename to chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_reauth_handler.h
index b01a7d9..4f82022c 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.h
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_reauth_handler.h
@@ -2,20 +2,20 @@
 // 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_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_REAUTH_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_REAUTH_HANDLER_H_
+#ifndef CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_REAUTH_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_REAUTH_HANDLER_H_
 
 #include <memory>
 #include "base/memory/weak_ptr.h"
 #include "base/values.h"
-// TODO(https://crbug.com/1164001): move to forward declaration.
-#include "chrome/browser/ash/login/saml/in_session_password_sync_manager.h"
 #include "chrome/browser/ui/webui/chromeos/login/check_passwords_against_cryptohome_helper.h"
 #include "chrome/browser/ui/webui/chromeos/login/online_login_helper.h"
 #include "content/public/browser/web_ui_message_handler.h"
 #include "net/cookies/cookie_access_result.h"
 
-namespace chromeos {
+namespace ash {
+
+class InSessionPasswordSyncManager;
 
 class LockScreenReauthHandler : public content::WebUIMessageHandler {
  public:
@@ -122,7 +122,7 @@
 
   std::unique_ptr<UserContext> user_context_;
 
-  std::unique_ptr<ash::CheckPasswordsAgainstCryptohomeHelper>
+  std::unique_ptr<CheckPasswordsAgainstCryptohomeHelper>
       check_passwords_against_cryptohome_helper_;
 
   std::unique_ptr<LoginClientCertUsageObserver>
@@ -136,12 +136,6 @@
   base::WeakPtrFactory<LockScreenReauthHandler> weak_factory_{this};
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove after the //chrome/browser/chromeos
-// source migration is finished.
-namespace ash {
-using ::chromeos::LockScreenReauthHandler;
-}
-
-#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_REAUTH_HANDLER_H_
+#endif  // CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_REAUTH_HANDLER_H_
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_start_reauth_ui.cc b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_start_reauth_ui.cc
similarity index 95%
rename from chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_start_reauth_ui.cc
rename to chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_start_reauth_ui.cc
index fe791b25..79b1f12 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_start_reauth_ui.cc
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_start_reauth_ui.cc
@@ -2,12 +2,12 @@
 // 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/chromeos/in_session_password_change/lock_screen_start_reauth_ui.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_start_reauth_ui.h"
 
 #include <memory>
 
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_reauth_handler.h"
 #include "chrome/browser/ui/webui/metrics_handler.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/browser_resources.h"
@@ -20,7 +20,7 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/chromeos/devicetype_utils.h"
 
-namespace chromeos {
+namespace ash {
 
 LockScreenStartReauthUI::LockScreenStartReauthUI(content::WebUI* web_ui)
     : ui::WebDialogUI(web_ui) {
@@ -120,4 +120,4 @@
 
 LockScreenStartReauthUI::~LockScreenStartReauthUI() = default;
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_start_reauth_ui.h b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_start_reauth_ui.h
new file mode 100644
index 0000000..5615899
--- /dev/null
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_start_reauth_ui.h
@@ -0,0 +1,31 @@
+// Copyright 2020 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_ASH_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_START_REAUTH_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_START_REAUTH_UI_H_
+
+#include "base/callback_list.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_reauth_handler.h"
+#include "ui/web_dialogs/web_dialog_ui.h"
+
+namespace ash {
+
+// For chrome:://lock-reauth
+class LockScreenStartReauthUI : public ui::WebDialogUI {
+ public:
+  explicit LockScreenStartReauthUI(content::WebUI* web_ui);
+  ~LockScreenStartReauthUI() override;
+
+  LockScreenReauthHandler* GetMainHandler() { return main_handler_; }
+
+ private:
+  // The main message handler.
+  LockScreenReauthHandler* main_handler_;
+
+  base::WeakPtrFactory<LockScreenStartReauthUI> weak_factory_{this};
+};
+
+}  // namespace ash
+
+#endif  // CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_START_REAUTH_UI_H_
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_dialogs.cc b/chrome/browser/ui/webui/ash/in_session_password_change/password_change_dialogs.cc
similarity index 96%
rename from chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_dialogs.cc
rename to chrome/browser/ui/webui/ash/in_session_password_change/password_change_dialogs.cc
index 99045320..7b724b0d 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_dialogs.cc
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/password_change_dialogs.cc
@@ -2,13 +2,13 @@
 // 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/chromeos/in_session_password_change/password_change_dialogs.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/password_change_dialogs.h"
 
 #include <memory>
 
 #include "base/bind.h"
 #include "base/json/json_writer.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/confirm_password_change_handler.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/confirm_password_change_handler.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/browser_resources.h"
 #include "chrome/grit/generated_resources.h"
@@ -18,7 +18,7 @@
 #include "ui/display/screen.h"
 #include "ui/strings/grit/ui_strings.h"
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 
@@ -193,4 +193,4 @@
   g_notification_dialog = nullptr;
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_dialogs.h b/chrome/browser/ui/webui/ash/in_session_password_change/password_change_dialogs.h
similarity index 83%
rename from chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_dialogs.h
rename to chrome/browser/ui/webui/ash/in_session_password_change/password_change_dialogs.h
index fe986449..762b711a 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_dialogs.h
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/password_change_dialogs.h
@@ -2,15 +2,15 @@
 // 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_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_PASSWORD_CHANGE_DIALOGS_H_
-#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_PASSWORD_CHANGE_DIALOGS_H_
+#ifndef CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_PASSWORD_CHANGE_DIALOGS_H_
+#define CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_PASSWORD_CHANGE_DIALOGS_H_
 
 #include <string>
 
 #include "chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h"
 #include "ui/web_dialogs/web_dialog_ui.h"
 
-namespace chromeos {
+namespace ash {
 
 // A modal system dialog without any frame decorating it.
 class BasePasswordDialog : public SystemWebDialogDelegate {
@@ -93,14 +93,6 @@
   ~UrgentPasswordExpiryNotificationDialog() override;
 };
 
-}  // namespace chromeos
-
-// TODO(https://crbug.com/1164001): remove after the //chrome/browser/chromeos
-// source migration is finished.
-namespace ash {
-using ::chromeos::ConfirmPasswordChangeDialog;
-using ::chromeos::PasswordChangeDialog;
-using ::chromeos::UrgentPasswordExpiryNotificationDialog;
 }  // namespace ash
 
-#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_PASSWORD_CHANGE_DIALOGS_H_
+#endif  // CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_PASSWORD_CHANGE_DIALOGS_H_
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_handler.cc b/chrome/browser/ui/webui/ash/in_session_password_change/password_change_handler.cc
similarity index 95%
rename from chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_handler.cc
rename to chrome/browser/ui/webui/ash/in_session_password_change/password_change_handler.cc
index 40c0d63..86bf79e 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_handler.cc
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/password_change_handler.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/browser/ui/webui/chromeos/in_session_password_change/password_change_handler.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/password_change_handler.h"
 
 #include <string>
 
@@ -17,7 +17,7 @@
 #include "components/prefs/pref_service.h"
 #include "components/user_manager/user_manager.h"
 
-namespace chromeos {
+namespace ash {
 
 PasswordChangeHandler::PasswordChangeHandler(
     const std::string& password_change_url)
@@ -72,4 +72,4 @@
                           weak_factory_.GetWeakPtr()));
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_handler.h b/chrome/browser/ui/webui/ash/in_session_password_change/password_change_handler.h
similarity index 73%
rename from chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_handler.h
rename to chrome/browser/ui/webui/ash/in_session_password_change/password_change_handler.h
index 0859411..52b188c7 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_handler.h
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/password_change_handler.h
@@ -2,14 +2,14 @@
 // 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_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_PASSWORD_CHANGE_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_PASSWORD_CHANGE_HANDLER_H_
+#ifndef CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_PASSWORD_CHANGE_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_PASSWORD_CHANGE_HANDLER_H_
 
 #include "base/memory/weak_ptr.h"
 #include "base/values.h"
 #include "content/public/browser/web_ui_message_handler.h"
 
-namespace chromeos {
+namespace ash {
 
 class PasswordChangeHandler : public content::WebUIMessageHandler {
  public:
@@ -32,6 +32,6 @@
   base::WeakPtrFactory<PasswordChangeHandler> weak_factory_{this};
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
-#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_PASSWORD_CHANGE_HANDLER_H_
+#endif  // CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_PASSWORD_CHANGE_HANDLER_H_
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_ui.cc b/chrome/browser/ui/webui/ash/in_session_password_change/password_change_ui.cc
similarity index 94%
rename from chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_ui.cc
rename to chrome/browser/ui/webui/ash/in_session_password_change/password_change_ui.cc
index e291e67..0f86b083 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_ui.cc
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/password_change_ui.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/browser/ui/webui/chromeos/in_session_password_change/password_change_ui.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/password_change_ui.h"
 
 #include <memory>
 
@@ -15,9 +15,9 @@
 #include "chrome/browser/ash/login/saml/password_expiry_notification.h"
 #include "chrome/browser/ash/policy/core/user_cloud_policy_manager_ash.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_dialogs.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_handler.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/urgent_password_expiry_notification_handler.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/password_change_dialogs.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/password_change_handler.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/urgent_password_expiry_notification_handler.h"
 #include "chrome/browser/ui/webui/webui_util.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/browser_resources.h"
@@ -38,7 +38,7 @@
 #include "ui/display/screen.h"
 #include "ui/strings/grit/ui_strings.h"
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 
@@ -198,4 +198,4 @@
 UrgentPasswordExpiryNotificationUI::~UrgentPasswordExpiryNotificationUI() =
     default;
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_ui.h b/chrome/browser/ui/webui/ash/in_session_password_change/password_change_ui.h
similarity index 81%
rename from chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_ui.h
rename to chrome/browser/ui/webui/ash/in_session_password_change/password_change_ui.h
index e977981..a717b0b 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_ui.h
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/password_change_ui.h
@@ -2,13 +2,13 @@
 // 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_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_PASSWORD_CHANGE_UI_H_
-#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_PASSWORD_CHANGE_UI_H_
+#ifndef CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_PASSWORD_CHANGE_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_PASSWORD_CHANGE_UI_H_
 
 #include "chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h"
 #include "ui/web_dialogs/web_dialog_ui.h"
 
-namespace chromeos {
+namespace ash {
 
 // For chrome:://password-change
 class PasswordChangeUI : public ui::WebDialogUI {
@@ -45,6 +45,6 @@
   ~UrgentPasswordExpiryNotificationUI() override;
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
-#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_PASSWORD_CHANGE_UI_H_
+#endif  // CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_PASSWORD_CHANGE_UI_H_
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/urgent_password_expiry_notification_handler.cc b/chrome/browser/ui/webui/ash/in_session_password_change/urgent_password_expiry_notification_handler.cc
similarity index 91%
rename from chrome/browser/ui/webui/chromeos/in_session_password_change/urgent_password_expiry_notification_handler.cc
rename to chrome/browser/ui/webui/ash/in_session_password_change/urgent_password_expiry_notification_handler.cc
index 3d4404ff..eeeab2e 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/urgent_password_expiry_notification_handler.cc
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/urgent_password_expiry_notification_handler.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/browser/ui/webui/chromeos/in_session_password_change/urgent_password_expiry_notification_handler.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/urgent_password_expiry_notification_handler.h"
 
 #include <string>
 
@@ -15,7 +15,7 @@
 #include "components/prefs/pref_service.h"
 #include "components/user_manager/user_manager.h"
 
-namespace chromeos {
+namespace ash {
 
 UrgentPasswordExpiryNotificationHandler::
     UrgentPasswordExpiryNotificationHandler() = default;
@@ -52,4 +52,4 @@
           weak_factory_.GetWeakPtr()));
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/urgent_password_expiry_notification_handler.h b/chrome/browser/ui/webui/ash/in_session_password_change/urgent_password_expiry_notification_handler.h
similarity index 74%
rename from chrome/browser/ui/webui/chromeos/in_session_password_change/urgent_password_expiry_notification_handler.h
rename to chrome/browser/ui/webui/ash/in_session_password_change/urgent_password_expiry_notification_handler.h
index a16d706e..899dce0 100644
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/urgent_password_expiry_notification_handler.h
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/urgent_password_expiry_notification_handler.h
@@ -2,14 +2,14 @@
 // 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_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_URGENT_PASSWORD_EXPIRY_NOTIFICATION_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_URGENT_PASSWORD_EXPIRY_NOTIFICATION_HANDLER_H_
+#ifndef CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_URGENT_PASSWORD_EXPIRY_NOTIFICATION_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_URGENT_PASSWORD_EXPIRY_NOTIFICATION_HANDLER_H_
 
 #include "base/memory/weak_ptr.h"
 #include "base/values.h"
 #include "content/public/browser/web_ui_message_handler.h"
 
-namespace chromeos {
+namespace ash {
 
 class UrgentPasswordExpiryNotificationHandler
     : public content::WebUIMessageHandler {
@@ -37,6 +37,6 @@
       this};
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
-#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_URGENT_PASSWORD_EXPIRY_NOTIFICATION_HANDLER_H_
+#endif  // CHROME_BROWSER_UI_WEBUI_ASH_IN_SESSION_PASSWORD_CHANGE_URGENT_PASSWORD_EXPIRY_NOTIFICATION_HANDLER_H_
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index 04a33ef..2eeda7c 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -260,15 +260,15 @@
 #include "chrome/browser/ui/webui/ash/crostini_installer/crostini_installer_ui.h"
 #include "chrome/browser/ui/webui/ash/crostini_upgrader/crostini_upgrader_ui.h"
 #include "chrome/browser/ui/webui/ash/emoji/emoji_ui.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_network_ui.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_start_reauth_ui.h"
+#include "chrome/browser/ui/webui/ash/in_session_password_change/password_change_ui.h"
 #include "chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.h"
 #include "chrome/browser/ui/webui/chromeos/bluetooth_pairing_dialog.h"
 #include "chrome/browser/ui/webui/chromeos/certificate_manager_dialog_ui.h"
 #include "chrome/browser/ui/webui/chromeos/cryptohome_ui.h"
 #include "chrome/browser/ui/webui/chromeos/drive_internals_ui.h"
 #include "chrome/browser/ui/webui/chromeos/human_presence_internals_ui.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_ui.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_start_reauth_ui.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_ui.h"
 #include "chrome/browser/ui/webui/chromeos/internet_config_dialog.h"
 #include "chrome/browser/ui/webui/chromeos/internet_detail_dialog.h"
 #include "chrome/browser/ui/webui/chromeos/launcher_internals/launcher_internals_ui.h"
@@ -942,14 +942,14 @@
             ash::prefs::kSamlInSessionPasswordChangeEnabled)) {
       return nullptr;
     }
-    return &NewWebUI<chromeos::PasswordChangeUI>;
+    return &NewWebUI<ash::PasswordChangeUI>;
   }
   if (url.host_piece() == chrome::kChromeUIConfirmPasswordChangeHost) {
     if (!profile->GetPrefs()->GetBoolean(
             ash::prefs::kSamlInSessionPasswordChangeEnabled)) {
       return nullptr;
     }
-    return &NewWebUI<chromeos::ConfirmPasswordChangeUI>;
+    return &NewWebUI<ash::ConfirmPasswordChangeUI>;
   }
   if (url.host_piece() ==
       chrome::kChromeUIUrgentPasswordExpiryNotificationHost) {
@@ -957,19 +957,19 @@
             ash::prefs::kSamlInSessionPasswordChangeEnabled)) {
       return nullptr;
     }
-    return &NewWebUI<chromeos::UrgentPasswordExpiryNotificationUI>;
+    return &NewWebUI<ash::UrgentPasswordExpiryNotificationUI>;
   }
   if (url.host_piece() == chrome::kChromeUILockScreenStartReauthHost) {
     if (!ash::ProfileHelper::IsLockScreenProfile(profile)) {
       return nullptr;
     }
-    return &NewWebUI<chromeos::LockScreenStartReauthUI>;
+    return &NewWebUI<ash::LockScreenStartReauthUI>;
   }
   if (url.host_piece() == chrome::kChromeUILockScreenNetworkHost) {
     if (!ash::ProfileHelper::IsLockScreenProfile(profile)) {
       return nullptr;
     }
-    return &NewWebUI<chromeos::LockScreenNetworkUI>;
+    return &NewWebUI<ash::LockScreenNetworkUI>;
   }
   if (url.host_piece() == ash::file_manager::kChromeUIFileManagerHost) {
     return &NewComponentUI<ash::file_manager::FileManagerUI,
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_start_reauth_ui.h b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_start_reauth_ui.h
deleted file mode 100644
index 9fd9b52..0000000
--- a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_start_reauth_ui.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2020 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_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_START_REAUTH_UI_H_
-#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_START_REAUTH_UI_H_
-
-#include "base/callback_list.h"
-#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.h"
-#include "ui/web_dialogs/web_dialog_ui.h"
-
-namespace chromeos {
-
-// For chrome:://lock-reauth
-class LockScreenStartReauthUI : public ui::WebDialogUI {
- public:
-  explicit LockScreenStartReauthUI(content::WebUI* web_ui);
-  ~LockScreenStartReauthUI() override;
-
-  LockScreenReauthHandler* GetMainHandler() { return main_handler_; }
-
- private:
-  // The main message handler.
-  LockScreenReauthHandler* main_handler_;
-
-  base::WeakPtrFactory<LockScreenStartReauthUI> weak_factory_{this};
-};
-
-}  // namespace chromeos
-
-// TODO(https://crbug.com/1164001): remove after the //chrome/browser/chromeos
-// source migration is finished.
-namespace ash {
-using ::chromeos::LockScreenStartReauthUI;
-}
-
-#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_START_REAUTH_UI_H_
diff --git a/chrome/browser/ui/webui/chromeos/login/online_login_helper.h b/chrome/browser/ui/webui/chromeos/login/online_login_helper.h
index bdef641..487cc35 100644
--- a/chrome/browser/ui/webui/chromeos/login/online_login_helper.h
+++ b/chrome/browser/ui/webui/chromeos/login/online_login_helper.h
@@ -139,4 +139,16 @@
 
 }  // namespace chromeos
 
+// TODO(https://crbug.com/1164001): remove when it moved to ash.
+namespace ash {
+using ::chromeos::OnlineLoginHelper;
+namespace login {
+using ::chromeos::login::BuildUserContextForGaiaSignIn;
+using ::chromeos::login::ExtractSamlPasswordAttributesEnabled;
+using ::chromeos::login::GaiaContext;
+using ::chromeos::login::GetUsertypeFromServicesString;
+using ::chromeos::login::SetCookieForPartition;
+}  // namespace login
+}  // namespace ash
+
 #endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_ONLINE_LOGIN_HELPER_H_
diff --git a/chrome/browser/ui/webui/realbox/BUILD.gn b/chrome/browser/ui/webui/realbox/BUILD.gn
index 40e5c11..7d2fc89 100644
--- a/chrome/browser/ui/webui/realbox/BUILD.gn
+++ b/chrome/browser/ui/webui/realbox/BUILD.gn
@@ -12,6 +12,7 @@
 
   public_deps = [
     "//chrome/common/search:mojo_bindings",
+    "//components/omnibox/browser:omnibox",
     "//mojo/public/mojom/base",
     "//skia/public/mojom",
     "//url/mojom:url_mojom_gurl",
diff --git a/chrome/browser/ui/webui/realbox/realbox.mojom b/chrome/browser/ui/webui/realbox/realbox.mojom
index 029ae30..1266f91 100644
--- a/chrome/browser/ui/webui/realbox/realbox.mojom
+++ b/chrome/browser/ui/webui/realbox/realbox.mojom
@@ -4,6 +4,7 @@
 
 module realbox.mojom;
 
+import "components/omnibox/browser/omnibox.mojom";
 import "mojo/public/mojom/base/string16.mojom";
 import "mojo/public/mojom/base/time.mojom";
 import "skia/public/mojom/skcolor.mojom";
@@ -139,6 +140,11 @@
                         bool ctrl_key,
                         bool meta_key,
                         bool shift_key);
+  // Informs the browser that the user has changed the selected suggestion. The
+  // new suggestion is located at |line|. |navigation_predictor|
+  // indicates the event that indicated navigation was likely.
+  OnNavigationLikely(uint8 line,
+    omnibox.mojom.NavigationPredictor navigation_predictor);
   // Deletes the AutocompleteMatch in the current results by |line| number if
   // it is deletable.
   DeleteAutocompleteMatch(uint8 line);
diff --git a/chrome/browser/ui/webui/realbox/realbox_handler.cc b/chrome/browser/ui/webui/realbox/realbox_handler.cc
index 4680ce4a..7dc4fb8 100644
--- a/chrome/browser/ui/webui/realbox/realbox_handler.cc
+++ b/chrome/browser/ui/webui/realbox/realbox_handler.cc
@@ -656,6 +656,17 @@
                              disposition, match.transition, false));
 }
 
+void RealboxHandler::OnNavigationLikely(
+    uint8_t line,
+    omnibox::mojom::NavigationPredictor navigation_predictor) {
+  if (auto* search_prefetch_service =
+          SearchPrefetchServiceFactory::GetForProfile(profile_)) {
+    AutocompleteMatch match(autocomplete_controller_->result().match_at(line));
+    search_prefetch_service->OnNavigationLikely(
+        line, match, navigation_predictor, web_contents_);
+  }
+}
+
 void RealboxHandler::OpenURL(const GURL& destination_url,
                              TemplateURLRef::PostContent* post_content,
                              WindowOpenDisposition disposition,
diff --git a/chrome/browser/ui/webui/realbox/realbox_handler.h b/chrome/browser/ui/webui/realbox/realbox_handler.h
index 7de86836..6d9a645 100644
--- a/chrome/browser/ui/webui/realbox/realbox_handler.h
+++ b/chrome/browser/ui/webui/realbox/realbox_handler.h
@@ -14,6 +14,7 @@
 #include "chrome/browser/ui/webui/realbox/realbox.mojom.h"
 #include "components/omnibox/browser/autocomplete_controller.h"
 #include "components/omnibox/browser/favicon_cache.h"
+#include "components/omnibox/browser/omnibox.mojom-shared.h"
 #include "components/url_formatter/spoof_checks/idna_metrics.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver.h"
@@ -84,6 +85,9 @@
                      bool ctrl_key,
                      bool meta_key,
                      bool shift_key) override;
+  void OnNavigationLikely(
+      uint8_t line,
+      omnibox::mojom::NavigationPredictor navigation_predictor) override;
 
   // AutocompleteController::Observer:
   void OnResultChanged(AutocompleteController* controller,
diff --git a/chrome/browser/ui/webui/settings/ash/cups_printers_handler.cc b/chrome/browser/ui/webui/settings/ash/cups_printers_handler.cc
index 6759cb6..d302b0a 100644
--- a/chrome/browser/ui/webui/settings/ash/cups_printers_handler.cc
+++ b/chrome/browser/ui/webui/settings/ash/cups_printers_handler.cc
@@ -304,10 +304,6 @@
       base::BindRepeating(&CupsPrintersHandler::HandleAddCupsPrinter,
                           base::Unretained(this)));
   web_ui()->RegisterMessageCallback(
-      "retrieveCupsPrinterPpd",
-      base::BindRepeating(&CupsPrintersHandler::HandleRetrieveCupsPrinterPpd,
-                          base::Unretained(this)));
-  web_ui()->RegisterMessageCallback(
       "reconfigureCupsPrinter",
       base::BindRepeating(&CupsPrintersHandler::HandleReconfigureCupsPrinter,
                           base::Unretained(this)));
@@ -434,45 +430,6 @@
                                   PrinterSetupResult::kEditSuccess);
 }
 
-void CupsPrintersHandler::HandleRetrieveCupsPrinterPpd(
-    const base::Value::List& args) {
-  CHECK_EQ(3U, args.size());
-
-  const std::string& callback_id = args[0].GetString();
-  const std::string& printer_id = args[1].GetString();
-  const std::string& printer_name = args[2].GetString();
-  const std::vector<uint8_t> empty_ppd;
-
-  PRINTER_LOG(DEBUG) << "Retrieving printer PPD for " << printer_id << "("
-                     << printer_name << ")";
-
-  DebugDaemonClient::Get()->CupsRetrievePrinterPpd(
-      printer_id,
-      base::BindOnce(&CupsPrintersHandler::OnRetrieveCupsPrinterPpd,
-                     weak_factory_.GetWeakPtr(), callback_id, printer_name),
-      base::BindOnce(&CupsPrintersHandler::OnRetrieveCupsPrinterPpd,
-                     weak_factory_.GetWeakPtr(), callback_id, printer_name,
-                     empty_ppd));
-}
-
-void CupsPrintersHandler::OnRetrieveCupsPrinterPpd(
-    const std::string& callback_id,
-    const std::string& printer_name,
-    const std::vector<uint8_t>& data) {
-  // Bundle printer metadata
-  base::Value::Dict info;
-  info.Set("printerName", printer_name);
-
-  if (data.empty()) {
-    RejectJavascriptCallback(base::Value(callback_id), info);
-  } else {
-    // Convert our ppd (array of bytes) into a string
-    const std::string ppd(data.begin(), data.end());
-    info.Set("ppd", ppd);
-    ResolveJavascriptCallback(base::Value(callback_id), info);
-  }
-}
-
 void CupsPrintersHandler::HandleRemoveCupsPrinter(
     const base::Value::List& args) {
   PRINTER_LOG(USER) << "Removing printer";
diff --git a/chrome/browser/ui/webui/settings/ash/cups_printers_handler.h b/chrome/browser/ui/webui/settings/ash/cups_printers_handler.h
index 61b72065..085ab8f91 100644
--- a/chrome/browser/ui/webui/settings/ash/cups_printers_handler.h
+++ b/chrome/browser/ui/webui/settings/ash/cups_printers_handler.h
@@ -82,7 +82,6 @@
   void HandleGetCupsEnterprisePrintersList(const base::Value::List& args);
   void HandleUpdateCupsPrinter(const base::Value::List& args);
   void HandleRemoveCupsPrinter(const base::Value::List& args);
-  void HandleRetrieveCupsPrinterPpd(const base::Value::List& args);
 
   // For a CupsPrinterInfo in |args|, retrieves the relevant PrinterInfo object
   // using an IPP call to the printer.
@@ -186,12 +185,6 @@
   // Attempt to add a discovered printer.
   void HandleAddDiscoveredPrinter(const base::Value::List& args);
 
-  // Called when we get a response from
-  // DebugDaemonClient::CupsRetrievePrinterPpd.
-  void OnRetrieveCupsPrinterPpd(const std::string& callback_id,
-                                const std::string& printer_name,
-                                const std::vector<uint8_t>& data);
-
   // Post printer setup callback.
   void OnAddedDiscoveredPrinter(const std::string& callback_id,
                                 const chromeos::Printer& printer,
diff --git a/chrome/browser/ui/webui/settings/ash/printing_section.cc b/chrome/browser/ui/webui/settings/ash/printing_section.cc
index d261755..263c371 100644
--- a/chrome/browser/ui/webui/settings/ash/printing_section.cc
+++ b/chrome/browser/ui/webui/settings/ash/printing_section.cc
@@ -117,15 +117,10 @@
       {"cupsPrintersTitle", IDS_SETTINGS_PRINTING_CUPS_PRINTERS},
       {"cupsPrintersLearnMoreLabel",
        IDS_SETTINGS_PRINTING_CUPS_PRINTERS_LEARN_MORE_LABEL},
-      {"cupsPrintersLearnMoreButtonTitle", IDS_SETTINGS_LEARN_MORE},
       {"addCupsPrinter", IDS_SETTINGS_PRINTING_CUPS_PRINTERS_ADD_PRINTER},
       {"editPrinter", IDS_SETTINGS_PRINTING_CUPS_PRINTERS_EDIT},
       {"viewPrinter", IDS_SETTINGS_PRINTING_CUPS_PRINTERS_VIEW},
       {"removePrinter", IDS_SETTINGS_PRINTING_CUPS_PRINTERS_REMOVE},
-      {"cupsPrintersViewPpd", IDS_SETTINGS_PRINTING_CUPS_PRINTERS_VIEW_PPD},
-      {"cupsPrintersViewPpdErrorMessage",
-       IDS_SETTINGS_PRINTING_CUPS_VIEW_PPD_ERROR_MESSAGE},
-      {"cupsPrintersPpdFor", IDS_SETTINGS_PRINTING_CUPS_PRINTERS_PPD_INTRO},
       {"setupPrinter", IDS_SETTINGS_PRINTING_CUPS_PRINTER_SETUP_BUTTON},
       {"setupPrinterAria",
        IDS_SETTINGS_PRINTING_CUPS_PRINTER_SETUP_BUTTON_ARIA},
@@ -204,8 +199,6 @@
        IDS_SETTINGS_PRINTING_CUPS_PRINTER_CONFIGURING_MESSAGE},
       {"printerManufacturer", IDS_SETTINGS_PRINTING_CUPS_PRINTER_MANUFACTURER},
       {"selectDriver", IDS_SETTINGS_PRINTING_CUPS_PRINTER_SELECT_DRIVER},
-      {"selectDriverEditDialog",
-       IDS_SETTINGS_PRINTING_CUPS_PRINTER_EDIT_SELECT_DRIVER},
       {"selectDriverButtonText",
        IDS_SETTINGS_PRINTING_CUPS_PRINTER_BUTTON_SELECT_DRIVER},
       {"selectDriverButtonAriaLabel",
diff --git a/chrome/browser/web_applications/isolated_web_apps/install_isolated_app_from_command_line.cc b/chrome/browser/web_applications/isolated_web_apps/install_isolated_app_from_command_line.cc
index f4d9db8..7fecf75 100644
--- a/chrome/browser/web_applications/isolated_web_apps/install_isolated_app_from_command_line.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/install_isolated_app_from_command_line.cc
@@ -15,9 +15,11 @@
 #include "base/functional/callback_forward.h"
 #include "base/functional/callback_helpers.h"
 #include "base/no_destructor.h"
+#include "base/strings/strcat.h"
 #include "base/strings/string_piece.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/commands/install_isolated_app_command.h"
+#include "chrome/browser/web_applications/isolation_data.h"
 #include "chrome/browser/web_applications/web_app_command_manager.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/browser/web_applications/web_app_url_loader.h"
@@ -51,50 +53,21 @@
   return web_contents;
 }
 
-void ScheduleInstallIsolatedApp(WebAppProvider& provider,
+void ScheduleInstallIsolatedApp(GURL url,
+                                IsolationData isolation_data,
+                                WebAppProvider& provider,
                                 Profile& profile,
-                                GURL url,
                                 base::OnceClosure callback) {
   DCHECK(url.is_valid());
   DCHECK(!callback.is_null());
 
   provider.command_manager().ScheduleCommand(
       std::make_unique<InstallIsolatedAppCommand>(
-          url,
-          IsolationData{IsolationData::DevModeProxy{.proxy_url = url.spec()}},
-          CreateWebContents(profile), std::make_unique<WebAppUrlLoader>(),
-          provider.install_finalizer(),
+          url, isolation_data, CreateWebContents(profile),
+          std::make_unique<WebAppUrlLoader>(), provider.install_finalizer(),
           base::BindOnce(&ReportInstallationResult).Then(std::move(callback))));
 }
 
-void InstallApplicationFromUrl(WebAppProvider& provider,
-                               Profile& profile,
-                               GURL url,
-                               base::OnceClosure callback) {
-  DCHECK(url.is_valid());
-  DCHECK(!callback.is_null());
-
-  provider.on_registry_ready().Post(
-      FROM_HERE, base::BindOnce(ScheduleInstallIsolatedApp, std::ref(provider),
-                                std::ref(profile), url, std::move(callback)));
-}
-
-base::RepeatingCallback<void(GURL url, base::OnceClosure callback)>
-CreateProductionInstallApplicationFromUrl(Profile& profile) {
-  WebAppProvider* provider = WebAppProvider::GetForWebApps(&profile);
-
-  // Web applications are not available on some platform and
-  // |WebAppProvider::GetForWebApps| returns nullptr in such cases.
-  //
-  // See |WebAppProvider::GetForWebApps| documentation for details.
-  if (provider == nullptr) {
-    return base::DoNothing();
-  }
-
-  return base::BindRepeating(InstallApplicationFromUrl, std::ref(*provider),
-                             std::ref(profile));
-}
-
 base::OnceClosure& GetNextDoneCallbackInstance() {
   static base::NoDestructor<base::OnceClosure> kInstance{base::NullCallback()};
   return *kInstance;
@@ -107,44 +80,64 @@
   GetNextDoneCallbackInstance() = std::move(done_callback);
 }
 
-absl::optional<GURL> GetAppToInstallFromCommandLine(
-    const base::CommandLine& command_line) {
+base::expected<absl::optional<IsolationData>, std::string>
+GetIsolationDataFromCommandLine(const base::CommandLine& command_line) {
   std::string switch_value =
       command_line.GetSwitchValueASCII(switches::kInstallIsolatedWebAppFromUrl);
 
+  if (switch_value.empty()) {
+    return absl::nullopt;
+  }
+
   GURL url{switch_value};
 
   if (!url.is_valid()) {
-    return absl::nullopt;
+    return base::unexpected(base::StrCat(
+        {"Invalid URL provided to --", switches::kInstallIsolatedWebAppFromUrl,
+         " flag: '", url.possibly_invalid_spec(), "'"}));
   }
 
-  return url;
-}
-
-void MaybeInstallAppFromCommandLine(
-    const base::CommandLine& command_line,
-    base::RepeatingCallback<void(GURL url, base::OnceClosure callback)>
-        install_application_from_url,
-    base::OnceClosure done) {
-  DCHECK(!done.is_null());
-
-  absl::optional<GURL> app_to_install =
-      GetAppToInstallFromCommandLine(command_line);
-  if (!app_to_install.has_value()) {
-    std::move(done).Run();
-    return;
-  }
-
-  install_application_from_url.Run(*app_to_install, std::move(done));
+  return IsolationData{IsolationData::DevModeProxy{.proxy_url = url.spec()}};
 }
 
 void MaybeInstallAppFromCommandLine(const base::CommandLine& command_line,
                                     Profile& profile) {
-  base::OnceClosure& done = GetNextDoneCallbackInstance();
+  base::OnceClosure& next_done_callback = GetNextDoneCallbackInstance();
+  base::OnceClosure done = next_done_callback.is_null()
+                               ? base::DoNothing()
+                               : std::move(next_done_callback);
 
-  MaybeInstallAppFromCommandLine(
-      command_line, CreateProductionInstallApplicationFromUrl(profile),
-      done.is_null() ? base::DoNothing() : std::move(done));
+  // Web applications are not available on some platforms and
+  // |WebAppProvider::GetForWebApps| returns nullptr in such cases.
+  //
+  // See |WebAppProvider::GetForWebApps| documentation for details.
+  WebAppProvider* provider = WebAppProvider::GetForWebApps(&profile);
+  if (provider == nullptr) {
+    std::move(done).Run();
+    return;
+  }
+
+  base::expected<absl::optional<IsolationData>, std::string> isolation_data =
+      GetIsolationDataFromCommandLine(command_line);
+  if (!isolation_data.has_value()) {
+    LOG(ERROR) << isolation_data.error();
+    std::move(done).Run();
+    return;
+  }
+  if (!isolation_data->has_value()) {
+    std::move(done).Run();
+    return;
+  }
+
+  // TODO(b/245352649): Replace with randomly generated isolated-app: URL.
+  GURL url(absl::get<IsolationData::DevModeProxy>(
+               isolation_data.value().value().content)
+               .proxy_url);
+
+  provider->on_registry_ready().Post(
+      FROM_HERE,
+      base::BindOnce(&ScheduleInstallIsolatedApp, url, **isolation_data,
+                     std::ref(*provider), std::ref(profile), std::move(done)));
 }
 
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/isolated_web_apps/install_isolated_app_from_command_line.h b/chrome/browser/web_applications/isolated_web_apps/install_isolated_app_from_command_line.h
index 899fd7b..f649a35 100644
--- a/chrome/browser/web_applications/isolated_web_apps/install_isolated_app_from_command_line.h
+++ b/chrome/browser/web_applications/isolated_web_apps/install_isolated_app_from_command_line.h
@@ -6,21 +6,22 @@
 #define CHROME_BROWSER_WEB_APPLICATIONS_ISOLATED_WEB_APPS_INSTALL_ISOLATED_APP_FROM_COMMAND_LINE_H_
 
 #include "base/callback.h"
+#include "base/types/expected.h"
+#include "chrome/browser/web_applications/isolation_data.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace base {
 class CommandLine;
 }
 
-class GURL;
 class Profile;
 
 namespace web_app {
 
 void SetNextInstallationDoneCallbackForTesting(base::OnceClosure done_callback);
 
-absl::optional<GURL> GetAppToInstallFromCommandLine(
-    const base::CommandLine& command_line);
+base::expected<absl::optional<IsolationData>, std::string>
+GetIsolationDataFromCommandLine(const base::CommandLine& command_line);
 
 void MaybeInstallAppFromCommandLine(const base::CommandLine& command_line,
                                     Profile& profile);
diff --git a/chrome/browser/web_applications/isolated_web_apps/install_isolated_app_from_command_line_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/install_isolated_app_from_command_line_unittest.cc
index 6b5768a0..a6a36c35 100644
--- a/chrome/browser/web_applications/isolated_web_apps/install_isolated_app_from_command_line_unittest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/install_isolated_app_from_command_line_unittest.cc
@@ -18,8 +18,54 @@
 namespace web_app {
 namespace {
 
-using ::testing::Eq;
-using ::testing::Optional;
+void DescribeOptionalIsolationData(
+    ::testing::MatchResultListener* result_listener,
+    base::expected<absl::optional<IsolationData>, std::string> arg) {
+  if (arg.has_value()) {
+    if (arg.value().has_value())
+      *result_listener << arg.value()->AsDebugValue();
+    else
+      *result_listener << "nullopt";
+  } else {
+    *result_listener << "an error with message: \"" << arg.error() << '"';
+  }
+}
+
+MATCHER_P(HasErrorWithSubstr,
+          substr,
+          std::string(negation ? "not " : "") +
+              " an error with a message containing: \"" + substr + '"') {
+  if (arg.has_value() || arg.error().find(substr) == std::string::npos) {
+    DescribeOptionalIsolationData(result_listener, arg);
+    return false;
+  }
+  return true;
+}
+
+MATCHER(HasNoValue, negation ? "not absent" : "absent") {
+  if (!arg.has_value() || arg.value().has_value()) {
+    DescribeOptionalIsolationData(result_listener, arg);
+    return false;
+  }
+  return true;
+}
+
+MATCHER_P(IsDevModeProxy,
+          proxy_url,
+          std::string(negation ? "isn't " : "Dev Mode proxy with URL: \"") +
+              proxy_url + '"') {
+  if (!arg.has_value() || !arg.value().has_value()) {
+    DescribeOptionalIsolationData(result_listener, arg);
+    return false;
+  }
+  const IsolationData::DevModeProxy* proxy =
+      absl::get_if<IsolationData::DevModeProxy>(&arg.value().value().content);
+  if (proxy == nullptr || GURL(proxy->proxy_url) != GURL(proxy_url)) {
+    DescribeOptionalIsolationData(result_listener, arg);
+    return false;
+  }
+  return true;
+}
 
 base::CommandLine CreateDefaultCommandLine(base::StringPiece flag_value) {
   base::CommandLine command_line{base::CommandLine::NoProgram::NO_PROGRAM};
@@ -35,35 +81,35 @@
 
 TEST_F(InstallIsolatedAppFromCommandLineFlagTest,
        InstallsAppFromCommandLineFlag) {
-  EXPECT_THAT(GetAppToInstallFromCommandLine(
+  EXPECT_THAT(GetIsolationDataFromCommandLine(
                   CreateDefaultCommandLine("http://example.com")),
-              Optional(Eq(GURL("http://example.com"))));
+              IsDevModeProxy("http://example.com"));
 }
 
 TEST_F(InstallIsolatedAppFromCommandLineFlagTest,
        InstallsDifferentAppFromCommandLineFlag) {
-  EXPECT_THAT(GetAppToInstallFromCommandLine(
+  EXPECT_THAT(GetIsolationDataFromCommandLine(
                   CreateDefaultCommandLine("http://different-example.com")),
-              Optional(Eq(GURL("http://different-example.com"))));
+              IsDevModeProxy("http://different-example.com"));
 }
 
 TEST_F(InstallIsolatedAppFromCommandLineFlagTest, NoneForInvalidUrls) {
   EXPECT_THAT(
-      GetAppToInstallFromCommandLine(CreateDefaultCommandLine("badurl")),
-      Eq(absl::nullopt));
+      GetIsolationDataFromCommandLine(CreateDefaultCommandLine("badurl")),
+      HasErrorWithSubstr("Invalid URL"));
 }
 
 TEST_F(InstallIsolatedAppFromCommandLineFlagTest,
        DoNotCallInstallationWhenFlagIsEmpty) {
-  EXPECT_THAT(GetAppToInstallFromCommandLine(CreateDefaultCommandLine("")),
-              Eq(absl::nullopt));
+  EXPECT_THAT(GetIsolationDataFromCommandLine(CreateDefaultCommandLine("")),
+              HasNoValue());
 }
 
 TEST_F(InstallIsolatedAppFromCommandLineFlagTest,
        DoNotCallInstallationWhenFlagIsNotPresent) {
   const base::CommandLine command_line{
       base::CommandLine::NoProgram::NO_PROGRAM};
-  EXPECT_THAT(GetAppToInstallFromCommandLine(command_line), Eq(absl::nullopt));
+  EXPECT_THAT(GetIsolationDataFromCommandLine(command_line), HasNoValue());
 }
 
 }  // namespace
diff --git a/chrome/browser/web_applications/manifest_update_manager.cc b/chrome/browser/web_applications/manifest_update_manager.cc
index 24aeac1..df0d3bf 100644
--- a/chrome/browser/web_applications/manifest_update_manager.cc
+++ b/chrome/browser/web_applications/manifest_update_manager.cc
@@ -4,8 +4,16 @@
 
 #include "chrome/browser/web_applications/manifest_update_manager.h"
 
+#include <map>
+#include <memory>
+#include <tuple>
+#include <utility>
+
 #include "base/command_line.h"
 #include "base/containers/contains.h"
+#include "base/containers/flat_map.h"
+#include "base/memory/raw_ptr.h"
+#include "base/memory/weak_ptr.h"
 #include "base/metrics/histogram_functions.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/web_applications/os_integration/os_integration_manager.h"
@@ -14,9 +22,48 @@
 #include "chrome/common/chrome_features.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings_types.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
 
 namespace web_app {
 
+class ManifestUpdateManager::PreUpdateWebContentsObserver
+    : public content::WebContentsObserver {
+ public:
+  PreUpdateWebContentsObserver(base::OnceClosure load_complete_callback,
+                               content::WebContents* contents,
+                               bool hang_task_callback_for_testing)
+      : content::WebContentsObserver(contents),
+        load_complete_callback_(std::move(load_complete_callback)),
+        hang_task_callback_for_testing_(hang_task_callback_for_testing) {}
+
+ private:
+  // content::WebContentsObserver:
+  void DidFinishLoad(content::RenderFrameHost* render_frame_host,
+                     const GURL& validated_url) override {
+    if (!render_frame_host || hang_task_callback_for_testing_)
+      return;
+
+    if (render_frame_host->GetParentOrOuterDocument() ||
+        !render_frame_host->IsInPrimaryMainFrame())
+      return;
+
+    Observe(nullptr);
+    if (load_complete_callback_)
+      std::move(load_complete_callback_).Run();
+  }
+
+  void WebContentsDestroyed() override {
+    Observe(nullptr);
+    if (load_complete_callback_)
+      std::move(load_complete_callback_).Run();
+  }
+
+  base::OnceClosure load_complete_callback_;
+  bool hang_task_callback_for_testing_;
+};
+
 constexpr base::TimeDelta kDelayBetweenChecks = base::Days(1);
 constexpr const char kDisableManifestUpdateThrottle[] =
     "disable-manifest-update-throttle";
@@ -57,7 +104,7 @@
 void ManifestUpdateManager::Shutdown() {
   install_manager_observation_.Reset();
 
-  tasks_.clear();
+  update_stages_.clear();
   started_ = false;
 }
 
@@ -85,22 +132,61 @@
     return;
   }
 
-  if (base::Contains(tasks_, *app_id))
+  if (base::Contains(update_stages_, *app_id)) {
     return;
+  }
 
   if (!MaybeConsumeUpdateCheck(url.DeprecatedGetOriginAsURL(), *app_id)) {
     NotifyResult(url, *app_id, ManifestUpdateResult::kThrottled);
     return;
   }
 
-  tasks_.insert_or_assign(
-      *app_id, std::make_unique<ManifestUpdateTask>(
-                   url, *app_id, web_contents,
-                   base::BindOnce(&ManifestUpdateManager::OnUpdateStopped,
-                                  base::Unretained(this)),
-                   hang_update_checks_for_testing_, *registrar_, *icon_manager_,
-                   ui_manager_, install_finalizer_, *os_integration_manager_,
-                   sync_bridge_));
+  auto load_observer = std::make_unique<PreUpdateWebContentsObserver>(
+      base::BindOnce(&ManifestUpdateManager::StartUpdateTaskAfterPageLoad,
+                     base::Unretained(this), *app_id,
+                     web_contents->GetWeakPtr()),
+      web_contents, hang_update_checks_for_testing_);
+
+  update_stages_.emplace(std::piecewise_construct,
+                         std::forward_as_tuple(*app_id),
+                         std::forward_as_tuple(url, std::move(load_observer)));
+}
+
+ManifestUpdateManager::UpdateStage::UpdateStage(
+    const GURL& url,
+    std::unique_ptr<PreUpdateWebContentsObserver> observer)
+    : url(url), observer(std::move(observer)) {}
+
+ManifestUpdateManager::UpdateStage::~UpdateStage() = default;
+
+void ManifestUpdateManager::StartUpdateTaskAfterPageLoad(
+    const AppId& app_id,
+    base::WeakPtr<content::WebContents> web_contents) {
+  auto update_stage_it = update_stages_.find(app_id);
+  DCHECK(update_stage_it != update_stages_.end());
+  UpdateStage& update_stage = update_stage_it->second;
+  GURL url(update_stage.url);
+  DCHECK(update_stage.update_task == nullptr &&
+         update_stage.observer != nullptr);
+
+  // If web_contents have been destroyed before page load,
+  // then no need of running the task.
+  if (!web_contents || web_contents->IsBeingDestroyed()) {
+    update_stages_.erase(app_id);
+    NotifyResult(url, app_id, ManifestUpdateResult::kWebContentsDestroyed);
+    return;
+  }
+
+  auto manifest_update_task = std::make_unique<ManifestUpdateTask>(
+      url, app_id, web_contents->GetWeakPtr(),
+      base::BindOnce(&ManifestUpdateManager::OnUpdateStopped,
+                     base::Unretained(this)),
+      *registrar_, *icon_manager_, ui_manager_, install_finalizer_,
+      *os_integration_manager_, sync_bridge_);
+
+  // Swap out the observer for the update task.
+  update_stage.observer.reset();
+  update_stage.update_task = std::move(manifest_update_task);
 }
 
 bool ManifestUpdateManager::IsUpdateConsumed(const AppId& app_id) {
@@ -116,20 +202,19 @@
 }
 
 bool ManifestUpdateManager::IsUpdateTaskPending(const AppId& app_id) {
-  return base::Contains(tasks_, app_id);
+  return base::Contains(update_stages_, app_id);
 }
 
 // WebAppInstallManager:
 void ManifestUpdateManager::OnWebAppWillBeUninstalled(const AppId& app_id) {
   DCHECK(started_);
-
-  auto it = tasks_.find(app_id);
-  if (it != tasks_.end()) {
-    NotifyResult(it->second->url(), app_id,
+  auto it = update_stages_.find(app_id);
+  if (it != update_stages_.end()) {
+    NotifyResult(it->second.url, app_id,
                  ManifestUpdateResult::kAppUninstalling);
-    tasks_.erase(it);
+    update_stages_.erase(it);
   }
-  DCHECK(!tasks_.contains(app_id));
+  DCHECK(!base::Contains(update_stages_, app_id));
   last_update_check_.erase(app_id);
 }
 
@@ -164,9 +249,11 @@
 
 void ManifestUpdateManager::OnUpdateStopped(const ManifestUpdateTask& task,
                                             ManifestUpdateResult result) {
-  DCHECK_EQ(&task, tasks_[task.app_id()].get());
+  auto update_task_it = update_stages_.find(task.app_id());
+  DCHECK(update_task_it != update_stages_.end());
+  DCHECK_EQ(&task, update_task_it->second.update_task.get());
   NotifyResult(task.url(), task.app_id(), result);
-  tasks_.erase(task.app_id());
+  update_stages_.erase(task.app_id());
 }
 
 void ManifestUpdateManager::SetResultCallbackForTesting(
@@ -195,9 +282,9 @@
   if (it != last_update_check_.end()) {
     last_update_check_.erase(app_id);
   }
-  // Manifest update scheduling can still fail if there is an existing tasks.
+  // Manifest update scheduling can still fail if there are existing tasks.
   // Destroy this to ensure the next load will trigger update.
-  tasks_.erase(app_id);
+  update_stages_.erase(app_id);
 }
 
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/manifest_update_manager.h b/chrome/browser/web_applications/manifest_update_manager.h
index 37dd9be..2c2adf4 100644
--- a/chrome/browser/web_applications/manifest_update_manager.h
+++ b/chrome/browser/web_applications/manifest_update_manager.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_WEB_APPLICATIONS_MANIFEST_UPDATE_MANAGER_H_
 #define CHROME_BROWSER_WEB_APPLICATIONS_MANIFEST_UPDATE_MANAGER_H_
 
+#include <map>
 #include <memory>
 
 #include "base/callback.h"
@@ -65,7 +66,6 @@
                    const absl::optional<AppId>& app_id,
                    content::WebContents* web_contents);
   bool IsUpdateConsumed(const AppId& app_id);
-  // bool ResetUpdateStateForTesting(const AppId& app_id)
   bool IsUpdateTaskPending(const AppId& app_id);
 
   // WebAppInstallManagerObserver:
@@ -87,6 +87,36 @@
   void ResetManifestThrottleForTesting(const AppId& app_id);
 
  private:
+  // This class is used to either observe the url loading or web_contents
+  // destruction before manifest update tasks can be scheduled. Once any
+  // of those events have been fired, observing is stopped.
+  class PreUpdateWebContentsObserver;
+
+  // Store information regarding the entire manifest update in different stages.
+  // The following steps are followed for the update:
+  // 1. The UpdateStage is initialized by passing an observer, who waits till
+  // page loading has finished. During the lifetime of the observer,
+  // the update_task stays uninitialized.
+  // 2. The update_task is initialized as soon as the observer fires a
+  // DidFinishLoad and the observer is destructed. This ensures that at any
+  // point, either the observer or the update_task exists, but not both. This
+  // helps reason about the entire process at different stages of its
+  // functionality. This class is owned by the ManifestUpdateManager, and is
+  // guaranteed to hold an observer OR an update_task always, but never both.
+  struct UpdateStage {
+    UpdateStage(const GURL& url,
+                std::unique_ptr<PreUpdateWebContentsObserver> observer);
+    ~UpdateStage();
+
+    GURL url;
+    std::unique_ptr<PreUpdateWebContentsObserver> observer;
+    std::unique_ptr<ManifestUpdateTask> update_task;
+  };
+
+  void StartUpdateTaskAfterPageLoad(
+      const AppId& app_id,
+      base::WeakPtr<content::WebContents> web_contents);
+
   bool MaybeConsumeUpdateCheck(const GURL& origin, const AppId& app_id);
   absl::optional<base::Time> GetLastUpdateCheckTime(const AppId& app_id) const;
   void SetLastUpdateCheckTime(const GURL& origin,
@@ -111,8 +141,7 @@
   base::ScopedObservation<WebAppInstallManager, WebAppInstallManagerObserver>
       install_manager_observation_{this};
 
-  base::flat_map<AppId, std::unique_ptr<ManifestUpdateTask>> tasks_;
-
+  std::map<AppId, UpdateStage> update_stages_;
   base::flat_map<AppId, base::Time> last_update_check_;
 
   absl::optional<base::Time> time_override_for_testing_;
diff --git a/chrome/browser/web_applications/manifest_update_task.cc b/chrome/browser/web_applications/manifest_update_task.cc
index 8e09c1b..a5e0c65d 100644
--- a/chrome/browser/web_applications/manifest_update_task.cc
+++ b/chrome/browser/web_applications/manifest_update_task.cc
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/feature_list.h"
+#include "base/memory/weak_ptr.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/no_destructor.h"
 #include "base/strings/utf_string_conversions.h"
@@ -241,16 +242,15 @@
 ManifestUpdateTask::ManifestUpdateTask(
     const GURL& url,
     const AppId& app_id,
-    content::WebContents* web_contents,
+    base::WeakPtr<content::WebContents> web_contents,
     StoppedCallback stopped_callback,
-    bool hang_for_testing,
     WebAppRegistrar& registrar,
     WebAppIconManager& icon_manager,
     WebAppUiManager* ui_manager,
     WebAppInstallFinalizer* install_finalizer,
     OsIntegrationManager& os_integration_manager,
     WebAppSyncBridge* sync_bridge)
-    : content::WebContentsObserver(web_contents),
+    : web_contents_(web_contents),
       registrar_(registrar),
       icon_manager_(icon_manager),
       ui_manager_(*ui_manager),
@@ -259,10 +259,8 @@
       sync_bridge_(sync_bridge),
       url_(url),
       app_id_(app_id),
-      stopped_callback_(std::move(stopped_callback)),
-      hang_for_testing_(hang_for_testing) {
-  // Task starts by waiting for DidFinishLoad() to be called.
-  stage_ = Stage::kPendingPageLoad;
+      stopped_callback_(std::move(stopped_callback)) {
+  Start();
 }
 
 ManifestUpdateTask::~ManifestUpdateTask() {
@@ -274,50 +272,39 @@
 #endif
 }
 
-// content::WebContentsObserver:
-void ManifestUpdateTask::DidFinishLoad(
-    content::RenderFrameHost* render_frame_host,
-    const GURL& validated_url) {
-  if (stage_ != Stage::kPendingPageLoad || hang_for_testing_)
+void ManifestUpdateTask::Start() {
+  // We perform this check at the start as an early exit in case
+  // web_contents are destroyed before the task has started as well
+  // as ensuring that the web_contents_ are not destroyed when the
+  // InstallableManager is being invoked.
+  if (IsWebContentsDestroyed()) {
+    DestroySelf(ManifestUpdateResult::kWebContentsDestroyed);
     return;
-
-  if (render_frame_host->GetParentOrOuterDocument())
-    return;
-
+  }
   stage_ = Stage::kPendingInstallableData;
   webapps::InstallableParams params;
   params.valid_primary_icon = true;
   params.valid_manifest = true;
   params.check_webapp_manifest_display = false;
-  webapps::InstallableManager::FromWebContents(web_contents())
+  webapps::InstallableManager::FromWebContents(web_contents_.get())
       ->GetData(params,
                 base::BindOnce(&ManifestUpdateTask::OnDidGetInstallableData,
                                AsWeakPtr()));
 }
 
-// content::WebContentsObserver:
-void ManifestUpdateTask::WebContentsDestroyed() {
-  switch (stage_) {
-    case Stage::kPendingPageLoad:
-    case Stage::kPendingInstallableData:
-    case Stage::kPendingIconDownload:
-    case Stage::kPendingIconReadFromDisk:
-    case Stage::kPendingAppIdentityCheck:
-      DestroySelf(ManifestUpdateResult::kWebContentsDestroyed);
-      return;
-    case Stage::kPendingWindowsClosed:
-    case Stage::kPendingMaybeReadExistingIcons:
-    case Stage::kPendingInstallation:
-    case Stage::kPendingAssociationsUpdate:
-      // These stages should have stopped listening to the web contents.
-      NOTREACHED() << static_cast<int>(stage_);
-      Observe(nullptr);
-      break;
-  }
+bool ManifestUpdateTask::IsWebContentsDestroyed() {
+  return !web_contents_ || web_contents_->IsBeingDestroyed();
 }
 
 void ManifestUpdateTask::OnDidGetInstallableData(
     const webapps::InstallableData& data) {
+  // At this point, the ManifestUpdateTask is still collecting data, and this
+  // check ensures that the web_contents are still alive by the time we
+  // load icon contents.
+  if (IsWebContentsDestroyed()) {
+    DestroySelf(ManifestUpdateResult::kWebContentsDestroyed);
+    return;
+  }
   DCHECK_EQ(stage_, Stage::kPendingInstallableData);
 
   if (!data.NoBlockingErrors()) {
@@ -325,7 +312,7 @@
     return;
   }
 
-  CHECK(!web_contents()->IsBeingDestroyed());
+  CHECK(!web_contents_->IsBeingDestroyed());
 
   install_info_.emplace();
   UpdateWebAppInfoFromManifest(data.manifest, data.manifest_url,
@@ -449,12 +436,18 @@
 }
 
 void ManifestUpdateTask::UpdateAfterWindowsClose() {
+  // Ensure that the web_contents are still alive when the profile is being
+  // constructed from the browser context.
+  if (IsWebContentsDestroyed()) {
+    DestroySelf(ManifestUpdateResult::kWebContentsDestroyed);
+    return;
+  }
   DCHECK(stage_ == Stage::kPendingInstallableData ||
          stage_ == Stage::kPendingAppIdentityCheck);
   stage_ = Stage::kPendingWindowsClosed;
 
   Profile* profile =
-      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
+      Profile::FromBrowserContext(web_contents_.get()->GetBrowserContext());
   keep_alive_ = std::make_unique<ScopedKeepAlive>(
       KeepAliveOrigin::APP_MANIFEST_UPDATE, KeepAliveRestartOption::DISABLED);
   if (!profile->IsOffTheRecord()) {
@@ -463,9 +456,6 @@
     profile_keep_alive_ = std::make_unique<ScopedProfileKeepAlive>(
         profile, ProfileKeepAliveOrigin::kWebAppUpdate);
   }
-
-  Observe(nullptr);
-
   if (BypassWindowCloseWaitingForTesting()) {
     OnAllAppWindowsClosed();
   } else {
@@ -479,6 +469,12 @@
 }
 
 void ManifestUpdateTask::LoadAndCheckIconContents() {
+  // We need this check to ensure that the web_contents_ are still alive
+  // when the icon_downloader_ has started.
+  if (IsWebContentsDestroyed()) {
+    DestroySelf(ManifestUpdateResult::kWebContentsDestroyed);
+    return;
+  }
   DCHECK_EQ(stage_, Stage::kPendingInstallableData);
   stage_ = Stage::kPendingIconDownload;
 
@@ -486,7 +482,7 @@
   base::flat_set<GURL> icon_urls = GetValidIconUrlsToDownload(*install_info_);
 
   icon_downloader_.emplace(
-      web_contents(), std::move(icon_urls),
+      web_contents_.get(), std::move(icon_urls),
       base::BindOnce(&ManifestUpdateTask::OnIconsDownloaded, AsWeakPtr()));
   icon_downloader_->SkipPageFavicons();
   icon_downloader_->FailAllIfAnyFail();
@@ -497,6 +493,13 @@
     IconsDownloadedResult result,
     IconsMap icons_map,
     DownloadedIconsHttpResults icons_http_results) {
+  // At this point the ManifestUpdateTask is still at the kPendingIconDownload
+  // stage, so it is better to do a web_contents check before ending all icon
+  // reads.
+  if (IsWebContentsDestroyed()) {
+    DestroySelf(ManifestUpdateResult::kWebContentsDestroyed);
+    return;
+  }
   DCHECK_EQ(stage_, Stage::kPendingIconDownload);
 
   // TODO(crbug.com/1238622): Report `result` and `icons_http_results` in
@@ -521,6 +524,13 @@
 
 void ManifestUpdateTask::OnAllIconsRead(IconsMap downloaded_icons_map,
                                         IconBitmaps disk_icon_bitmaps) {
+  // We still need to ensure that the web_contents_ are kept alive throughout
+  // the app identity check call to invoke the web_app identity update dialog
+  // in the end.
+  if (IsWebContentsDestroyed()) {
+    DestroySelf(ManifestUpdateResult::kWebContentsDestroyed);
+    return;
+  }
   DCHECK_EQ(stage_, Stage::kPendingIconReadFromDisk);
 
   if (disk_icon_bitmaps.empty()) {
@@ -651,7 +661,7 @@
 
   ui_manager_.ShowWebAppIdentityUpdateDialog(
       app_id_, title_change, icon_change, old_title, new_title, *before_icon,
-      *after_icon, web_contents(),
+      *after_icon, web_contents_.get(),
       base::BindOnce(&ManifestUpdateTask::OnPostAppIdentityUpdateCheck,
                      AsWeakPtr()));
 
@@ -661,6 +671,12 @@
 
 void ManifestUpdateTask::OnPostAppIdentityUpdateCheck(
     AppIdentityUpdate app_identity_update_allowed) {
+  // Perform an early exit if the web_contents are destroyed before calling
+  // UpdateAfterWindowsClose().
+  if (IsWebContentsDestroyed()) {
+    DestroySelf(ManifestUpdateResult::kWebContentsDestroyed);
+    return;
+  }
   DCHECK_EQ(stage_, Stage::kPendingAppIdentityCheck);
 
   app_identity_update_allowed_ =
@@ -694,6 +710,12 @@
 
 void ManifestUpdateTask::OnAllShortcutsMenuIconsRead(
     ShortcutsMenuIconBitmaps disk_shortcuts_menu_icon_bitmaps) {
+  // Perform an early exit if the web_contents are destroyed before calling
+  // UpdateAfterWindowsClose().
+  if (IsWebContentsDestroyed()) {
+    DestroySelf(ManifestUpdateResult::kWebContentsDestroyed);
+    return;
+  }
   DCHECK_EQ(stage_, Stage::kPendingAppIdentityCheck);
 
   DCHECK(install_info_.has_value());
@@ -746,8 +768,6 @@
   DCHECK_EQ(stage_, Stage::kPendingAppIdentityCheck);
   stage_ = Stage::kPendingAssociationsUpdate;
 
-  Observe(nullptr);
-
   if (!IsUpdateNeededForWebAppOriginAssociations()) {
     DestroySelf(ManifestUpdateResult::kAppUpToDate);
     return;
diff --git a/chrome/browser/web_applications/manifest_update_task.h b/chrome/browser/web_applications/manifest_update_task.h
index e17f454..bd8432d3 100644
--- a/chrome/browser/web_applications/manifest_update_task.h
+++ b/chrome/browser/web_applications/manifest_update_task.h
@@ -17,7 +17,6 @@
 #include "components/keep_alive_registry/scoped_keep_alive.h"
 #include "components/services/app_service/public/cpp/file_handler.h"
 #include "components/services/app_service/public/cpp/protocol_handler_info.h"
-#include "content/public/browser/web_contents_observer.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace webapps {
@@ -154,8 +153,7 @@
 //  - Wait for all app windows to be closed.
 //  - Reinstall the web app using the fetched data.
 class ManifestUpdateTask final
-    : public base::SupportsWeakPtr<ManifestUpdateTask>,
-      public content::WebContentsObserver {
+    : public base::SupportsWeakPtr<ManifestUpdateTask> {
  public:
   using UpdatePendingCallback = base::OnceCallback<void(const GURL& url)>;
   using StoppedCallback = base::OnceCallback<void(const ManifestUpdateTask&,
@@ -170,9 +168,8 @@
 
   ManifestUpdateTask(const GURL& url,
                      const AppId& app_id,
-                     content::WebContents* web_contents,
+                     base::WeakPtr<content::WebContents> web_contents,
                      StoppedCallback stopped_callback,
-                     bool hang_for_testing,
                      WebAppRegistrar& registrar,
                      WebAppIconManager& icon_manager,
                      WebAppUiManager* ui_manager,
@@ -180,19 +177,14 @@
                      OsIntegrationManager& os_integration_manager,
                      WebAppSyncBridge* sync_bridge);
 
-  ~ManifestUpdateTask() override;
+  ~ManifestUpdateTask();
 
   const GURL& url() const { return url_; }
   const AppId& app_id() const { return app_id_; }
-
-  // content::WebContentsObserver:
-  void DidFinishLoad(content::RenderFrameHost* render_frame_host,
-                     const GURL& validated_url) override;
-  void WebContentsDestroyed() override;
+  void Start();
 
  private:
   enum class Stage {
-    kPendingPageLoad,
     kPendingInstallableData,
     kPendingIconDownload,
     kPendingIconReadFromDisk,
@@ -202,7 +194,14 @@
     kPendingInstallation,
     kPendingAssociationsUpdate,
   };
-
+  // We perform this check for the following Stages:
+  // kPendingInstallableData
+  // kPendingIconDownload
+  // kPendingIconReadFromDisk
+  // kPendingAppIdentityCheck
+  // For all other stages, we no longer need to observe the web_contents
+  // and the upgrade can proceed as expected.
+  bool IsWebContentsDestroyed();
   void OnDidGetInstallableData(const webapps::InstallableData& data);
   bool IsUpdateNeededForManifest() const;
   void LoadAndCheckIconContents();
@@ -230,6 +229,7 @@
                               OsHooksErrors os_hooks_errors);
   void DestroySelf(ManifestUpdateResult result);
 
+  base::WeakPtr<content::WebContents> web_contents_;
   WebAppRegistrar& registrar_;
   WebAppIconManager& icon_manager_;
   WebAppUiManager& ui_manager_;
@@ -249,7 +249,6 @@
   const GURL url_;
   const AppId app_id_;
   StoppedCallback stopped_callback_;
-  bool hang_for_testing_ = false;
   bool app_identity_update_allowed_ = false;
 
 #if DCHECK_IS_ON()
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model.cc b/chrome/browser/webauthn/authenticator_request_dialog_model.cc
index d90e984..d95b0c5 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_model.cc
+++ b/chrome/browser/webauthn/authenticator_request_dialog_model.cc
@@ -1097,29 +1097,23 @@
       !is_get_assertion && kShowCreatePlatformPasskeyStep &&
       base::FeatureList::IsEnabled(
           device::kWebAuthnNewDiscoverableCredentialsUi);
-
-  // Advance to the platform authenticator for:
-  // - getAssertion requests with a matching platform credential
-  // - makeCredential requests with attachment=platform
   if (base::Contains(transport_availability_.available_transports,
                      AuthenticatorTransport::kInternal) &&
       (transport_availability_.has_platform_authenticator_credential ==
            device::FidoRequestHandlerBase::RecognizedCredential::
                kHasRecognizedCredential ||
-       (show_create_passkey_step &&
-        transport_availability_.available_transports.size() == 1)) &&
+       show_create_passkey_step) &&
       !use_conditional_mediation_) {
     priority_transport = AuthenticatorTransport::kInternal;
   }
 
-  std::vector<AuthenticatorTransport> transports_to_list_if_active = {
-      AuthenticatorTransport::kUsbHumanInterfaceDevice,
-  };
-
+  std::vector<AuthenticatorTransport> transports_to_list_if_active;
   if (!use_conditional_mediation_) {
     // Conditional requests offer platform credentials through the autofill UI.
     transports_to_list_if_active.push_back(AuthenticatorTransport::kInternal);
   }
+  transports_to_list_if_active.push_back(
+      AuthenticatorTransport::kUsbHumanInterfaceDevice);
 
   const auto kCable = AuthenticatorTransport::kHybrid;
   bool include_add_phone_option = false;
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc b/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc
index 463f6dc..625f092 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc
+++ b/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc
@@ -204,26 +204,26 @@
       {mc, {usb}, {}, {}, {t(usb)}, usb_ui},
       {ga, {usb}, {}, {}, {t(usb)}, usb_ui},
       // ... otherwise should the selection sheet.
-      {mc, {usb, internal}, {}, {}, {t(usb), t(internal)}, mss},
-      {ga, {usb, internal}, {}, {}, {t(usb), t(internal)}, mss},
+      {ga, {usb, cable}, {}, {}, {t(usb), add}, mss},
+      {ga, {usb, cable}, {}, {}, {t(usb), add}, mss},
 
       // If the platform authenticator has a credential it should activate.
-      {ga, {usb, internal}, {has_plat}, {}, {t(usb), t(internal)}, plat_ui},
+      {ga, {usb, internal}, {has_plat}, {}, {t(internal), t(usb)}, plat_ui},
       // ... but with an empty allow list the user should be prompted first.
       {ga,
        {usb, internal},
        {has_plat, one_cred, empty_al},
        {},
-       {t(usb), t(internal)},
+       {t(internal), t(usb)},
        use_pk},
       {ga,
        {usb, internal},
        {has_plat, two_cred, empty_al},
        {},
-       {t(usb), t(internal)},
+       {t(internal), t(usb)},
        use_pk_multi},
 
-      // MakeCredential with attachmemt=platform shows the 'Create a passkey'
+      // MakeCredential with attachment=platform shows the 'Create a passkey'
       // step, but only on macOS. On other OSes, we defer to the platform.
       {mc,
        {internal},
@@ -236,6 +236,19 @@
        plat_ui
 #endif
       },
+      // MakeCredential with attachment=undefined also shows the 'Create a
+      // passkey' step on macOS. On other OSes, we show mechanism selection.
+      {mc,
+       {usb, internal},
+       {},
+       {},
+       {t(internal), t(usb)},
+#if BUILDFLAG(IS_MAC)
+       create_pk
+#else
+       mss
+#endif
+      },
 
       // If the Windows API is available without caBLE, it should activate.
       {mc, {}, {has_winapi}, {}, {winapi}, plat_ui},
@@ -581,6 +594,7 @@
     model.AddObserver(&mock_observer);
 
     TransportAvailabilityInfo transports_info;
+    transports_info.request_type = RequestType::kGetAssertion;
     transports_info.available_transports = kAllTransportsWithoutCable;
 
     EXPECT_CALL(mock_observer, OnStepTransition());
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 30fac55..67a4b6b 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1665597506-69424600cd8ac8ad57eee50de5f83fc641d993fb.profdata
+chrome-linux-main-1665619171-90641809996091b3900226b153e8d65e0e684708.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index b5448bb..0ff0e1b 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1665586466-388e9b01906698ec86d653efab7419ec232700bb.profdata
+chrome-win32-main-1665608401-142598f65ff3db4c2e10fcbbda472a1687f04ae5.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 5c1fa16..69d21ed 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1665597506-133eabc042ccf9f1157cba488b723bcca2cfd73d.profdata
+chrome-win64-main-1665619171-129809cf0c5d17cfbe48fe83724001d688021aa0.profdata
diff --git a/chrome/renderer/chrome_render_frame_observer.cc b/chrome/renderer/chrome_render_frame_observer.cc
index 03106e33..06ccfad 100644
--- a/chrome/renderer/chrome_render_frame_observer.cc
+++ b/chrome/renderer/chrome_render_frame_observer.cc
@@ -246,15 +246,15 @@
 void ChromeRenderFrameObserver::DidFinishLoad() {
   WebLocalFrame* frame = render_frame()->GetWebFrame();
   // Don't do anything for subframes.
-  if (frame->Parent())
+  if (frame->Parent() || frame->IsInFencedFrameTree())
     return;
 
   GURL osdd_url = frame->GetDocument().OpenSearchDescriptionURL();
   if (!osdd_url.is_empty()) {
-    mojo::AssociatedRemote<chrome::mojom::OpenSearchDescriptionDocumentHandler>
+    mojo::Remote<chrome::mojom::OpenSearchDescriptionDocumentHandler>
         osdd_handler;
-    render_frame()->GetRemoteAssociatedInterfaces()->GetInterface(
-        &osdd_handler);
+    render_frame()->GetBrowserInterfaceBroker()->GetInterface(
+        osdd_handler.BindNewPipeAndPassReceiver());
     osdd_handler->PageHasOpenSearchDescriptionDocument(
         frame->GetDocument().Url(), osdd_url);
   }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 78af560..26fae9f 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -6657,6 +6657,7 @@
       "../browser/metrics/desktop_session_duration/touch_mode_stats_tracker_unittest.cc",
       "../browser/metrics/power/power_metrics_reporter_unittest.cc",
       "../browser/metrics/power/power_metrics_unittest.cc",
+      "../browser/metrics/power/process_monitor_unittest.cc",
       "../browser/metrics/power/usage_scenario_unittest.cc",
       "../browser/metrics/tab_stats/tab_stats_data_store_unittest.cc",
       "../browser/metrics/tab_stats/tab_stats_tracker_unittest.cc",
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/BUILD.gn b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/BUILD.gn
index eb6b658..e46b06070 100644
--- a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/BUILD.gn
+++ b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/BUILD.gn
@@ -26,6 +26,8 @@
     "create_file/test.js",
     "delete_entry/sw.js",
     "delete_entry/test.js",
+    "evil/sw.js",
+    "evil/test.js",
     "get_all/sw.js",
     "get_all/test.js",
     "helpers.js",
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/evil/manifest.json b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/evil/manifest.json
new file mode 100644
index 0000000..836695e
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/evil/manifest.json
@@ -0,0 +1,23 @@
+{
+  // chrome-extension://pkplfbidichfdicaijlchgnapepdginl
+  "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtDfX9dHNh948bt00YhZBm3P6E5QLaOt+v8kXVtibQfiPtOD2FTScB/f0wX/EQWVO7BkaSOsRkTPcPIgocyMPYr2FLgqGLFlYT9nQpKJZUFNF5oJ5rG6Nv7ppf4zEB3j6da1IBRTz2yOZ+6O1TMZxol/V62/QcqrJeggsHTEPGLdr9Ua4b1Ka0xKJnJngZljsbw93FI1o+P9dAh5BS6wTPiZI/vmJVjvMTkSTnaZ3n9Go2t7A0XLcSxLcVyuLAd2mAvSN0mIviOukdM66wr7llif71nKuUt+4qvlr/r9HfwzN6pA4jkwhtS1UD+3CmB+wsHwsnohNcuu4FIQ6rgq/7QIDAQAB",
+  "name": "chrome.fileSystemProvider.onReadFileRequested (evil edge-case tests)",
+  "version": "0.1",
+  "manifest_version": 3,
+  "description":
+      "Test for chrome.fileSystemProvider.onReadFileRequested() in service workers. Testing evil behavior of providing extensions.",
+  "permissions": [
+    "fileSystemProvider",
+    {
+      "fileSystem": ["requestFileSystem", "write"]
+    },
+    "fileManagerPrivate"
+  ],
+  "file_system_provider_capabilities": {
+    "source": "device"
+  },
+  "background": {
+    "service_worker": "sw.js",
+    "type": "module"
+  }
+}
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/evil/sw.js b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/evil/sw.js
new file mode 100644
index 0000000..ac074135
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/evil/sw.js
@@ -0,0 +1,7 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {serviceWorkerMain} from '/_test_resources/api_test/file_system_provider/service_worker/provider.js';
+
+serviceWorkerMain(self);
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/evil/test.html b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/evil/test.html
new file mode 100644
index 0000000..9980fda0
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/evil/test.html
@@ -0,0 +1 @@
+<script type="module" src="test.js"></script>
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/evil/test.js b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/evil/test.js
new file mode 100644
index 0000000..0273455
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/evil/test.js
@@ -0,0 +1,97 @@
+// 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 {mountTestFileSystem, openFile, readTextFromBlob, remoteProvider} from '/_test_resources/api_test/file_system_provider/service_worker/helpers.js';
+// For shared constants.
+import {TestFileSystemProvider} from '/_test_resources/api_test/file_system_provider/service_worker/provider.js';
+
+async function main() {
+  await navigator.serviceWorker.ready;
+  const fileSystem = await mountTestFileSystem();
+
+  chrome.test.runTests([
+    // Tests that returning a too big chunk (4 times larger than the file size,
+    // and also much more than requested 1 KB of data) makes the request fail.
+    async function returnTooLargeChunk() {
+      try {
+        const fileEntry = await fileSystem.getFileEntry(
+            TestFileSystemProvider.FILE_TOO_LARGE_CHUNK,
+            {create: false},
+        );
+        const file = await openFile(fileEntry);
+        // Read 1 KB of data.
+        const fileSlice = file.slice(0, 1024);
+        try {
+          await readTextFromBlob(fileSlice);
+          chrome.test.fail('Reading should fail.');
+        } catch (e) {
+          chrome.test.assertEq('NotReadableError', e.name);
+          chrome.test.succeed();
+        }
+      } catch (e) {
+        chrome.test.fail(e);
+      }
+    },
+
+    // Tests that calling a success callback with a non-existing request id
+    // doesn't cause any harm.
+    async function invalidCallback() {
+      try {
+        const fileEntry = await fileSystem.getFileEntry(
+            TestFileSystemProvider.FILE_INVALID_CALLBACK,
+            {create: false},
+        );
+        const file = await openFile(fileEntry);
+        // Read 1 KB of data.
+        const fileSlice = file.slice(0, 1024);
+        try {
+          await readTextFromBlob(fileSlice);
+          chrome.test.fail('Reading should fail.');
+        } catch (e) {
+          chrome.test.assertEq('NotReadableError', e.name);
+          chrome.test.succeed();
+        }
+      } catch (e) {
+        chrome.test.fail(e);
+      }
+    },
+
+    // Test that reading from files with negative size is not allowed (empty
+    // result is returned).
+    async function negativeSize() {
+      try {
+        const fileEntry = await fileSystem.getFileEntry(
+            TestFileSystemProvider.FILE_NEGATIVE_SIZE,
+            {create: false},
+        );
+        const file = await openFile(fileEntry);
+        // Read 1 KB of data.
+        const fileSlice = file.slice(0, 1024);
+        const text = await readTextFromBlob(fileSlice);
+        chrome.test.assertEq('', text);
+        chrome.test.succeed();
+      } catch (e) {
+        chrome.test.fail(e);
+      }
+    },
+
+    // Tests that accesses to  files containing ".." do not work.
+    async function relativeName() {
+      try {
+        await fileSystem.getFileEntry(
+            '../../../b.txt',
+            {create: false},
+        );
+        chrome.test.fail('Opening a file should fail.');
+      } catch (e) {
+        chrome.test.assertEq('NotFoundError', e.name);
+        // The call to open a file should not even reach the provider.
+        chrome.test.assertEq(
+            0, await remoteProvider.getEventCount('onFileOpenRequested'));
+        chrome.test.succeed();
+      }
+    }
+  ]);
+}
+
+main();
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/helpers.js b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/helpers.js
index a265b8a..f1cce7ad 100644
--- a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/helpers.js
+++ b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/helpers.js
@@ -225,6 +225,12 @@
   continueRequest: async (requestId) =>
       callServiceWorker('continueRequest', requestId),
   /**
+   * @param {string} eventName
+   * @returns {!Promise<number>}
+   */
+  getEventCount: async (eventName) =>
+      callServiceWorker('getEventCount', eventName),
+  /**
    * @param {string} filePath
    * @returns {!Promise<string>}
    */
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/provider.js b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/provider.js
index 51d33250..b79d9ba 100644
--- a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/provider.js
+++ b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/provider.js
@@ -56,6 +56,14 @@
   return {dirPath: path.join('/'), fileName};
 }
 
+/**
+ * @param {string} text
+ * @returns {!ArrayBuffer}
+ */
+function textToBuffer(text) {
+  return new TextEncoder().encode(text).buffer;
+}
+
 class Entry {
   /**
    * @param {{
@@ -150,6 +158,22 @@
         entry.metadata.size = 6 * 1024 * 1024 * 1024;
         return entry;
       })(),
+      // Read returns more data than asked for.
+      Entry.file(
+          TestFileSystemProvider.FILE_TOO_LARGE_CHUNK,
+          new Date(2014, 1, 25, 7, 36, 12), 'A'.repeat(1024 * 2)),
+      // Read handlers invokes both success and error callbacks.
+      Entry.file(
+          TestFileSystemProvider.FILE_INVALID_CALLBACK,
+          new Date(2014, 1, 25, 7, 36, 12), 'A'.repeat(1024 * 2)),
+      // File with negative size.
+      (() => {
+        const entry = Entry.file(
+            TestFileSystemProvider.FILE_NEGATIVE_SIZE,
+            new Date(2014, 1, 25, 7, 36, 12), 'A'.repeat(1024 * 2));
+        entry.metadata.size = -entry.metadata.size;
+        return entry;
+      })(),
     ]);
 
     /**
@@ -307,6 +331,19 @@
   }
 
   /**
+   * Called by the test. Gets the count of events for an event name, to check
+   * that there's been no events without blocking. When using, ensure that "no
+   * event" condition is gated by some other condition you can wait for (e.g. a
+   * request failing and returning a result).
+   *
+   * @param {string} eventName
+   * @returns {number}
+   */
+  getEventCount(eventName) {
+    return this.getEventQueue(eventName).items.length;
+  }
+
+  /**
    * Called by the tests to control provider configuration for different test
    * scenarios.
    * @param {string} key
@@ -714,21 +751,39 @@
       return;
     }
 
+    const filePath = this.openedFiles[options.openRequestId];
+    const entry = this.findEntryByPath(filePath);
+    if (!entry) {
+      onError(chrome.fileSystemProvider.ProviderError.INVALID_OPERATION);
+      return;
+    }
+
     const sendFileInChunks = (file) => {
-      const array = new TextEncoder().encode(file.contents);
+      const buffer = textToBuffer(file.contents);
       const CHUNK_SIZE = 5;
-      for (let i = 0; i < array.length; i += CHUNK_SIZE) {
+      for (let i = 0; i < buffer.byteLength; i += CHUNK_SIZE) {
         onSuccess(
-            /*data=*/ array.slice(i, Math.min(array.length, i + CHUNK_SIZE))
-                .buffer,
-            /*hasMore=*/ i + CHUNK_SIZE < array.length);
+            /*data=*/ buffer.slice(
+                i, Math.min(buffer.byteLength, i + CHUNK_SIZE)),
+            /*hasMore=*/ i + CHUNK_SIZE < buffer.byteLength);
       }
     };
 
-    const filePath = this.openedFiles[options.openRequestId];
-    if (filePath === '/' + TestFileSystemProvider.FILE_READ_SUCCESS) {
-      const entry = this.findEntryByPath(filePath);
-      sendFileInChunks(entry);
+    if (filePath === '/' + TestFileSystemProvider.FILE_TOO_LARGE_CHUNK) {
+      // Invalid file: returns more data than the file size.
+      const buffer = textToBuffer('A'.repeat(entry.metadata.size * 4));
+      onSuccess(buffer, /*hasMore=*/ true);
+      onSuccess(buffer, /*hasMore=*/ true);
+      onSuccess(buffer, /*hasMore=*/ true);
+      onSuccess(buffer, /*hasMore=*/ false);
+      return;
+    }
+
+    if (filePath === '/' + TestFileSystemProvider.FILE_INVALID_CALLBACK) {
+      // Invalid file: invokes both success and error callbacks.
+      const buffer = textToBuffer('A'.repeat(options.length));
+      onError(chrome.fileSystemProvider.ProviderError.NOT_FOUND);
+      onSuccess(buffer, /*hasMore=*/ false);
       return;
     }
 
@@ -749,7 +804,6 @@
 
     if (filePath === '/' + TestFileSystemProvider.FILE_STALL_READ) {
       // Block the read until it's unblocked.
-      const entry = this.findEntryByPath(filePath);
       this.stallRequest('onReadFileRequested', options)
           .then(() => sendFileInChunks(entry));
       return;
@@ -763,16 +817,15 @@
         return;
       }
       // The return value does not matter, so just return a string of "A"s.
+      // Encoded length is the same as string length for ASCII.
       onSuccess(
-          /*data=*/ new Uint8Array(options.length)
-              .fill('A'.charCodeAt(0))
-              .buffer,
+          /*data=*/ textToBuffer('A'.repeat(options.length)),
           /*hasMore=*/ false,
       );
       return;
     }
 
-    onError(chrome.fileSystemProvider.ProviderError.INVALID_OPERATION);
+    sendFileInChunks(entry);
   }
 
   /**
@@ -852,16 +905,15 @@
     }
 
     // Create an array with enough space for new data.
-    const oldArray = new TextEncoder().encode(entry.contents || '');
-    const newLength =
-        Math.max(oldArray.length, options.offset + options.data.byteLength);
-    const newArray = new Uint8Array(new ArrayBuffer(newLength));
+    const prevContents = textToBuffer(entry.contents || '');
+    const newLength = Math.max(
+        prevContents.byteLength, options.offset + options.data.byteLength);
+    const newContents = new Uint8Array(new ArrayBuffer(newLength));
     // Write existing data and new data.
-    newArray.set(oldArray, 0);
-    newArray.set(new Uint8Array(options.data), options.offset);
+    newContents.set(new Uint8Array(prevContents), 0);
+    newContents.set(new Uint8Array(options.data), options.offset);
     // Save the new file as text.
-    const newContents = new TextDecoder().decode(newArray);
-    entry.contents = newContents;
+    entry.contents = new TextDecoder().decode(newContents);
     metadata.size = newContents.length;
     onSuccess();
   }
@@ -970,6 +1022,30 @@
 TestFileSystemProvider.FILE_BIG = 'read-big.txt';
 
 /**
+ * File read requests return more data than asked for.
+ *
+ * @type {string}
+ * @const
+ */
+TestFileSystemProvider.FILE_TOO_LARGE_CHUNK = 'read-too-large-chunks.txt';
+
+/**
+ * File read requests call both error and success callbacks.
+ *
+ * @type {string}
+ * @const
+ */
+TestFileSystemProvider.FILE_INVALID_CALLBACK = 'read-invalid-callback.txt';
+
+/**
+ * File with negative size in metadata.
+ *
+ * @type {string}
+ * @const
+ */
+TestFileSystemProvider.FILE_NEGATIVE_SIZE = 'negative-size.txt';
+
+/**
  * Initial contents of default testing files.
  *
  * @type {string}
diff --git a/chrome/test/data/pdf/fullscreen_test.ts b/chrome/test/data/pdf/fullscreen_test.ts
index bf41392..3fa33f9 100644
--- a/chrome/test/data/pdf/fullscreen_test.ts
+++ b/chrome/test/data/pdf/fullscreen_test.ts
@@ -23,35 +23,6 @@
   await eventToPromise('fullscreenchange', scroller);
 }
 
-async function enterAndExitFullscreen(): Promise<void> {
-  // Subsequent calls to requestFullScreen() fail with an "API can only be
-  // initiated by a user gesture" error, so we need to run with user
-  // gesture.
-  function enterFullscreenWithUserGesture(): Promise<void> {
-    return new Promise(res => {
-      chrome.test.runWithUserGesture(() => {
-        ensureFullscreen().then(res);
-      });
-    });
-  }
-
-  await enterFullscreenWithUserGesture();
-  document.exitFullscreen();
-  await eventToPromise('fullscreenchange', scroller);
-}
-
-async function assertEnterAndExitFullscreenWithType(fittingType: FittingType):
-    Promise<void> {
-  // Fullscreen must be exited at the start of this test in order for it to
-  // function properly.
-  chrome.test.assertTrue(document.fullscreenElement === null);
-
-  viewer.viewport.setFittingType(fittingType);
-  await enterAndExitFullscreen();
-  chrome.test.assertTrue(document.fullscreenElement === null);
-  chrome.test.assertEq(fittingType, viewer.viewport.fittingType);
-}
-
 const tests = [
   async function testFullscreen() {
     chrome.test.assertTrue(scroller !== null);
@@ -167,6 +138,9 @@
       chrome.test.succeed();
     });
   },
+  // Note: The following test needs to be the last one, because subsequent calls
+  // to requestFullScreen() fail with an "API can only be initiated by a user
+  // gesture" error.
   async function testFocusAfterExiting() {
     await ensureFullscreen();
     document.exitFullscreen();
@@ -174,32 +148,6 @@
     chrome.test.assertEq('EMBED', getDeepActiveElement()!.nodeName);
     chrome.test.succeed();
   },
-  async function testZoomAfterExiting() {
-    // Fullscreen must be exited at the start of this test in order for it to
-    // function properly.
-    chrome.test.assertTrue(document.fullscreenElement === null);
-
-    // Zoom before fullscreen should be restored after entering and exiting
-    // fullscreen.
-    viewer.viewport.setZoom(0.5);
-    await enterAndExitFullscreen();
-    chrome.test.assertEq(0.5, viewer.viewport.getZoom());
-    chrome.test.assertEq(FittingType.NONE, viewer.viewport.fittingType);
-
-    chrome.test.succeed();
-  },
-  async function testEnterAndExitFullscreenWithType_FitToPage() {
-    assertEnterAndExitFullscreenWithType(FittingType.FIT_TO_PAGE);
-    chrome.test.succeed();
-  },
-  async function testEnterAndExitFullscreenWithType_FitToWidth() {
-    assertEnterAndExitFullscreenWithType(FittingType.FIT_TO_WIDTH);
-    chrome.test.succeed();
-  },
-  async function testEnterAndExitFullscreenWithType_FitToHeight() {
-    assertEnterAndExitFullscreenWithType(FittingType.FIT_TO_HEIGHT);
-    chrome.test.succeed();
-  },
 ];
 
 chrome.test.runTests(tests);
diff --git a/chrome/test/data/webui/app_home/test_app_home_browser_proxy.ts b/chrome/test/data/webui/app_home/test_app_home_browser_proxy.ts
index 1575120..f85e839f 100644
--- a/chrome/test/data/webui/app_home/test_app_home_browser_proxy.ts
+++ b/chrome/test/data/webui/app_home/test_app_home_browser_proxy.ts
@@ -19,6 +19,8 @@
   getApps() {
     return Promise.resolve(this.app_);
   }
+
+  uninstallApp(_appId: string) {}
 }
 
 export class TestAppHomeBrowserProxy implements BrowserProxy {
diff --git a/chrome/test/data/webui/new_tab_page/realbox/realbox_test.ts b/chrome/test/data/webui/new_tab_page/realbox/realbox_test.ts
index a00c06a..7909fc03 100644
--- a/chrome/test/data/webui/new_tab_page/realbox/realbox_test.ts
+++ b/chrome/test/data/webui/new_tab_page/realbox/realbox_test.ts
@@ -6,6 +6,7 @@
 import 'chrome://new-tab-page/new_tab_page.js';
 
 import {$$, decodeString16, mojoString16, RealboxBrowserProxy, RealboxElement, RealboxIconElement, RealboxMatchElement} from 'chrome://new-tab-page/new_tab_page.js';
+import {NavigationPredictor} from 'chrome://new-tab-page/omnibox.mojom-webui.js';
 import {AutocompleteMatch} from 'chrome://new-tab-page/realbox.mojom-webui.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {getDeepActiveElement} from 'chrome://resources/js/util.js';
@@ -2530,6 +2531,68 @@
     assertEquals(1, testProxy.handler.getCallCount('executeAction'));
   });
 
+  //============================================================================
+  // Test Forwarding Events
+  //============================================================================
+
+  test('arrow events are sent to handler', async () => {
+    realbox.$.input.value = 'he';
+    realbox.$.input.dispatchEvent(new InputEvent('input'));
+
+    const matches = [createSearchMatch()];
+    testProxy.callbackRouterRemote.autocompleteResultChanged({
+      input: mojoString16(realbox.$.input.value.trimLeft()),
+      matches,
+      suggestionGroupsMap: {},
+    });
+    await testProxy.callbackRouterRemote.$.flushForTesting();
+    assertTrue(areMatchesShowing());
+
+    const arrowDownEvent = new KeyboardEvent('keydown', {
+      bubbles: true,
+      cancelable: true,
+      composed: true,  // So it propagates across shadow DOM boundary.
+      key: 'ArrowDown',
+    });
+    realbox.$.input.dispatchEvent(arrowDownEvent);
+
+    await testProxy.handler.whenCalled('onNavigationLikely').then((args) => {
+      assertEquals(0, args.line);
+      assertEquals(
+          NavigationPredictor.kUpOrDownArrowButton, args.navigationPredictor);
+    });
+  });
+
+  test('mouse down events are sent to handler', async () => {
+    realbox.$.input.value = 'he';
+    realbox.$.input.dispatchEvent(new InputEvent('input'));
+
+    const matches = [createSearchMatch()];
+    testProxy.callbackRouterRemote.autocompleteResultChanged({
+      input: mojoString16(realbox.$.input.value.trimLeft()),
+      matches,
+      suggestionGroupsMap: {},
+    });
+    await testProxy.callbackRouterRemote.$.flushForTesting();
+    assertTrue(areMatchesShowing());
+
+    const matchEls =
+        realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match');
+
+    const mouseDown = new MouseEvent('mousedown', {
+      bubbles: true,
+      button: 0,
+      cancelable: true,
+      composed: true,  // So it propagates across shadow DOM boundary.
+    });
+    matchEls[0]!.$.contents.dispatchEvent(mouseDown);
+
+    await testProxy.handler.whenCalled('onNavigationLikely').then((args) => {
+      assertEquals(0, args.line);
+      assertEquals(NavigationPredictor.kMouseDown, args.navigationPredictor);
+    });
+  });
+
   suite('Lens search', () => {
     test('Lens search button does not show by default', () => {
       // Assert
diff --git a/chrome/test/data/webui/new_tab_page/realbox/test_realbox_browser_proxy.ts b/chrome/test/data/webui/new_tab_page/realbox/test_realbox_browser_proxy.ts
index 901d9e4..4cc76fc 100644
--- a/chrome/test/data/webui/new_tab_page/realbox/test_realbox_browser_proxy.ts
+++ b/chrome/test/data/webui/new_tab_page/realbox/test_realbox_browser_proxy.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 {NavigationPredictor} from 'chrome://new-tab-page/omnibox.mojom-webui.js';
 import {PageCallbackRouter, PageHandlerInterface, PageRemote} from 'chrome://new-tab-page/realbox.mojom-webui.js';
 import {String16} from 'chrome://resources/mojo/mojo/public/mojom/base/string16.mojom-webui.js';
 import {TimeDelta, TimeTicks} from 'chrome://resources/mojo/mojo/public/mojom/base/time.mojom-webui.js';
@@ -21,6 +22,7 @@
       'deleteAutocompleteMatch',
       'executeAction',
       'logCharTypedToRepaintLatency',
+      'onNavigationLikely',
       'openAutocompleteMatch',
       'queryAutocomplete',
       'stopAutocomplete',
@@ -71,6 +73,10 @@
     });
   }
 
+  onNavigationLikely(line: number, navigationPredictor: NavigationPredictor) {
+    this.methodCalled('onNavigationLikely', {line, navigationPredictor});
+  }
+
   queryAutocomplete(input: String16, preventInlineAutocomplete: boolean) {
     this.methodCalled('queryAutocomplete', {input, preventInlineAutocomplete});
   }
diff --git a/chrome/test/data/webui/settings/chromeos/network_summary_item_test.js b/chrome/test/data/webui/settings/chromeos/network_summary_item_test.js
index 61c15e5..2fe00aa2 100644
--- a/chrome/test/data/webui/settings/chromeos/network_summary_item_test.js
+++ b/chrome/test/data/webui/settings/chromeos/network_summary_item_test.js
@@ -316,6 +316,32 @@
         });
 
     test(
+        'kPortal shows signin text and opens network list on arrow click',
+        async function() {
+          const showNetworksFiredPromise =
+              eventToPromise('show-networks', netSummaryItem);
+
+          initWithPortalState(true /* flagEnabled */, PortalState.kPortal);
+          assertTrue(netSummaryItem.shadowRoot.querySelector('#networkState')
+                         .classList.contains('warning-message'));
+          assertFalse(netSummaryItem.shadowRoot.querySelector('#networkState')
+                          .classList.contains('network-state'));
+          assertEquals(
+              netSummaryItem.getNetworkStateText_(),
+              netSummaryItem.i18n('networkListItemSignIn'));
+          assertEquals(netSummaryItem.getTitleText_(), testName);
+
+          // Verify clicking network summary item arrow icon will show networks
+          const networkSummaryItemRowArrowIcon =
+              netSummaryItem.shadowRoot.querySelector(
+                  '#networkSummaryItemRowArrowIcon');
+          assertTrue(!!networkSummaryItemRowArrowIcon);
+          networkSummaryItemRowArrowIcon.click();
+          flush();
+          await showNetworksFiredPromise;
+        });
+
+    test(
         'kProxyAuthRequired shows signin text and opens portal signin on click',
         function() {
           initWithPortalState(
diff --git a/chrome/utility/BUILD.gn b/chrome/utility/BUILD.gn
index aae3ce6..cf4a826 100644
--- a/chrome/utility/BUILD.gn
+++ b/chrome/utility/BUILD.gn
@@ -184,7 +184,6 @@
     deps += [
       "//ash/services/ime:lib",
       "//ash/services/ime/public/mojom",
-      "//ash/services/recording",
       "//chrome/services/file_util",
       "//chrome/services/sharing",
       "//chromeos/ash/components/assistant:buildflags",
@@ -194,6 +193,7 @@
       "//chromeos/ash/components/trash_service/public/mojom",
       "//chromeos/ash/services/nearby/public/mojom:mojom",
       "//chromeos/ash/services/quick_pair",
+      "//chromeos/ash/services/recording",
       "//chromeos/services/tts",
       "//chromeos/services/tts/public/mojom",
     ]
diff --git a/chrome/utility/DEPS b/chrome/utility/DEPS
index 93a0b6c..4b79cbb 100644
--- a/chrome/utility/DEPS
+++ b/chrome/utility/DEPS
@@ -1,7 +1,6 @@
 include_rules = [
   "+ash/services/ime/ime_service.h",
   "+ash/services/ime/public/mojom",
-  "+ash/services/recording/recording_service.h",
   "+chrome/grit",
   "+chrome/installer/util",
   "+chrome/services/ipp_parser/ipp_parser.h",
@@ -35,6 +34,7 @@
   "+chromeos/ash/services/assistant/audio_decoder",
   "+chromeos/ash/services/libassistant/libassistant_service.h",
   "+chromeos/ash/services/nearby",
+  "+chromeos/ash/services/recording/recording_service.h",
   "+chromeos/ash/services/quick_pair/quick_pair_service.h",
   "+chromeos/components/quick_answers/public",
   "+chromeos/services/tts",
diff --git a/chrome/utility/services.cc b/chrome/utility/services.cc
index d9fcafb..456d520 100644
--- a/chrome/utility/services.cc
+++ b/chrome/utility/services.cc
@@ -120,7 +120,6 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/services/ime/ime_service.h"
 #include "ash/services/ime/public/mojom/input_engine.mojom.h"
-#include "ash/services/recording/recording_service.h"
 #include "chrome/services/sharing/sharing_impl.h"
 #include "chromeos/ash/components/assistant/buildflags.h"  // nogncheck
 #include "chromeos/ash/components/local_search_service/local_search_service.h"
@@ -129,6 +128,7 @@
 #include "chromeos/ash/components/trash_service/trash_service_impl.h"
 #include "chromeos/ash/services/nearby/public/mojom/sharing.mojom.h"  // nogncheck
 #include "chromeos/ash/services/quick_pair/quick_pair_service.h"
+#include "chromeos/ash/services/recording/recording_service.h"
 #include "chromeos/services/tts/public/mojom/tts_service.mojom.h"
 #include "chromeos/services/tts/tts_service.h"
 
diff --git a/chromeos/ash/components/dbus/debug_daemon/debug_daemon_client.cc b/chromeos/ash/components/dbus/debug_daemon/debug_daemon_client.cc
index 25dd8a6..1822802 100644
--- a/chromeos/ash/components/dbus/debug_daemon/debug_daemon_client.cc
+++ b/chromeos/ash/components/dbus/debug_daemon/debug_daemon_client.cc
@@ -555,22 +555,6 @@
                        std::move(error_callback)));
   }
 
-  void CupsRetrievePrinterPpd(
-      const std::string& name,
-      DebugDaemonClient::CupsRetrievePrinterPpdCallback callback,
-      base::OnceClosure error_callback) override {
-    dbus::MethodCall method_call(debugd::kDebugdInterface,
-                                 debugd::kCupsRetrievePpd);
-    dbus::MessageWriter writer(&method_call);
-    writer.AppendString(name);
-
-    debugdaemon_proxy_->CallMethod(
-        &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
-        base::BindOnce(&DebugDaemonClientImpl::OnRetrievedPrinterPpd,
-                       weak_ptr_factory_.GetWeakPtr(), std::move(callback),
-                       std::move(error_callback)));
-  }
-
   void StartPluginVmDispatcher(const std::string& owner_id,
                                const std::string& lang,
                                PluginVmDispatcherCallback callback) override {
@@ -1001,24 +985,6 @@
       std::move(error_callback).Run();
   }
 
-  void OnRetrievedPrinterPpd(CupsRetrievePrinterPpdCallback callback,
-                             base::OnceClosure error_callback,
-                             dbus::Response* response) {
-    size_t length = 0;
-    const uint8_t* bytes = nullptr;
-
-    if (!(response &&
-          dbus::MessageReader(response).PopArrayOfBytes(&bytes, &length)) ||
-        length == 0 || bytes == nullptr) {
-      LOG(ERROR) << "Failed to retrieve printer PPD";
-      std::move(error_callback).Run();
-      return;
-    }
-
-    std::vector<uint8_t> data(bytes, bytes + length);
-    std::move(callback).Run(data);
-  }
-
   void OnStartPluginVmDispatcher(PluginVmDispatcherCallback callback,
                                  dbus::Response* response,
                                  dbus::ErrorResponse* error) {
diff --git a/chromeos/ash/components/dbus/debug_daemon/debug_daemon_client.h b/chromeos/ash/components/dbus/debug_daemon/debug_daemon_client.h
index 80019848..3b45275 100644
--- a/chromeos/ash/components/dbus/debug_daemon/debug_daemon_client.h
+++ b/chromeos/ash/components/dbus/debug_daemon/debug_daemon_client.h
@@ -281,18 +281,6 @@
                                  CupsRemovePrinterCallback callback,
                                  base::OnceClosure error_callback) = 0;
 
-  // A callback to handle the result of CupsRetrievePrinterPpd.
-  using CupsRetrievePrinterPpdCallback =
-      base::OnceCallback<void(const std::vector<uint8_t>& ppd)>;
-
-  // Calls the debugd method to retrieve a PPD.  |name| is the printer name as
-  // registered in CUPS. |callback| is called with a string containing the PPD
-  // data. |error_callback| will be called if there was an error retrieving the
-  // PPD.
-  virtual void CupsRetrievePrinterPpd(const std::string& name,
-                                      CupsRetrievePrinterPpdCallback callback,
-                                      base::OnceClosure error_callback) = 0;
-
   // A callback to handle the result of
   // StartPluginVmDispatcher/StopPluginVmDispatcher.
   using PluginVmDispatcherCallback = base::OnceCallback<void(bool success)>;
diff --git a/chromeos/ash/components/dbus/debug_daemon/fake_debug_daemon_client.cc b/chromeos/ash/components/dbus/debug_daemon/fake_debug_daemon_client.cc
index a9d87ca..64ab5e7b 100644
--- a/chromeos/ash/components/dbus/debug_daemon/fake_debug_daemon_client.cc
+++ b/chromeos/ash/components/dbus/debug_daemon/fake_debug_daemon_client.cc
@@ -295,16 +295,6 @@
       FROM_HERE, base::BindOnce(std::move(callback), has_printer));
 }
 
-void FakeDebugDaemonClient::CupsRetrievePrinterPpd(
-    const std::string& name,
-    CupsRetrievePrinterPpdCallback callback,
-    base::OnceClosure error_callback) {
-  std::vector<uint8_t> fake_ppd{'F', 'a', 'k', 'e', ' ', 'P', 'P',
-                                'D', ' ', 'd', 'a', 't', 'a'};
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), fake_ppd));
-}
-
 void FakeDebugDaemonClient::StartPluginVmDispatcher(
     const std::string& /* owner_id */,
     const std::string& /* lang */,
diff --git a/chromeos/ash/components/dbus/debug_daemon/fake_debug_daemon_client.h b/chromeos/ash/components/dbus/debug_daemon/fake_debug_daemon_client.h
index b99ce96..a20d618 100644
--- a/chromeos/ash/components/dbus/debug_daemon/fake_debug_daemon_client.h
+++ b/chromeos/ash/components/dbus/debug_daemon/fake_debug_daemon_client.h
@@ -114,9 +114,6 @@
   void CupsRemovePrinter(const std::string& name,
                          CupsRemovePrinterCallback callback,
                          base::OnceClosure error_callback) override;
-  void CupsRetrievePrinterPpd(const std::string& name,
-                              CupsRetrievePrinterPpdCallback callback,
-                              base::OnceClosure error_callback) override;
   void StartPluginVmDispatcher(const std::string& owner_id,
                                const std::string& lang,
                                PluginVmDispatcherCallback callback) override;
diff --git a/chromeos/ash/components/drivefs/fake_drivefs.cc b/chromeos/ash/components/drivefs/fake_drivefs.cc
index 63a15d0..4d3ef70 100644
--- a/chromeos/ash/components/drivefs/fake_drivefs.cc
+++ b/chromeos/ash/components/drivefs/fake_drivefs.cc
@@ -94,6 +94,7 @@
   bool pinned = false;
   bool hosted = false;
   bool shared = false;
+  bool available_offline = false;
   std::string original_name;
   mojom::Capabilities capabilities;
   mojom::FolderFeature folder_feature;
@@ -288,6 +289,7 @@
                               const std::string& mime_type,
                               const std::string& original_name,
                               bool pinned,
+                              bool available_offline,
                               bool shared,
                               const mojom::Capabilities& capabilities,
                               const mojom::FolderFeature& folder_feature,
@@ -303,6 +305,9 @@
   if (pinned) {
     stored_metadata.pinned = true;
   }
+  if (available_offline) {
+    stored_metadata.available_offline = true;
+  }
   if (shared) {
     stored_metadata.shared = true;
   }
@@ -348,7 +353,8 @@
 
   const auto& stored_metadata = metadata_[path];
   metadata->pinned = stored_metadata.pinned;
-  metadata->available_offline = stored_metadata.pinned;
+  metadata->available_offline =
+      stored_metadata.pinned || stored_metadata.available_offline;
   metadata->shared = stored_metadata.shared;
 
   metadata->content_mime_type = stored_metadata.mime_type;
diff --git a/chromeos/ash/components/drivefs/fake_drivefs.h b/chromeos/ash/components/drivefs/fake_drivefs.h
index cccf1c5d..6b57747b 100644
--- a/chromeos/ash/components/drivefs/fake_drivefs.h
+++ b/chromeos/ash/components/drivefs/fake_drivefs.h
@@ -60,6 +60,7 @@
                    const std::string& mime_type,
                    const std::string& original_name,
                    bool pinned,
+                   bool available_offline,
                    bool shared,
                    const mojom::Capabilities& capabilities,
                    const mojom::FolderFeature& folder_feature,
diff --git a/chromeos/ash/components/login/auth/public/sync_trusted_vault_keys.cc b/chromeos/ash/components/login/auth/public/sync_trusted_vault_keys.cc
index 6c841a8..daffcf5 100644
--- a/chromeos/ash/components/login/auth/public/sync_trusted_vault_keys.cc
+++ b/chromeos/ash/components/login/auth/public/sync_trusted_vault_keys.cc
@@ -28,35 +28,35 @@
 };
 
 absl::optional<KeyMaterialAndVersion> ParseSingleEncryptionKey(
-    const base::Value& js_object) {
+    const base::Value::Dict& js_object) {
   const base::Value::BlobStorage* key_material =
-      js_object.FindBlobKey(kKeyMaterialDictKey);
+      js_object.FindBlob(kKeyMaterialDictKey);
   if (key_material == nullptr) {
     return absl::nullopt;
   }
 
-  return KeyMaterialAndVersion{
-      *key_material, js_object.FindIntKey(kVersionDictKey).value_or(0)};
+  return KeyMaterialAndVersion{*key_material,
+                               js_object.FindInt(kVersionDictKey).value_or(0)};
 }
 
 absl::optional<SyncTrustedVaultKeys::TrustedRecoveryMethod>
-ParseSingleTrustedRecoveryMethod(const base::Value& js_object) {
+ParseSingleTrustedRecoveryMethod(const base::Value::Dict& js_object) {
   const base::Value::BlobStorage* public_key =
-      js_object.FindBlobKey(kPublicKeyDictKey);
+      js_object.FindBlob(kPublicKeyDictKey);
   if (public_key == nullptr) {
     return absl::nullopt;
   }
 
   SyncTrustedVaultKeys::TrustedRecoveryMethod method;
   method.public_key = *public_key;
-  method.type_hint = js_object.FindIntKey(kMethodTypeHintDictKey).value_or(0);
+  method.type_hint = js_object.FindInt(kMethodTypeHintDictKey).value_or(0);
   return method;
 }
 
 template <typename T>
 std::vector<T> ParseList(
     const base::Value::List* list,
-    const base::RepeatingCallback<absl::optional<T>(const base::Value&)>&
+    const base::RepeatingCallback<absl::optional<T>(const base::Value::Dict&)>&
         entry_parser) {
   if (list == nullptr) {
     return {};
@@ -64,7 +64,7 @@
 
   std::vector<T> parsed_list;
   for (const base::Value& list_entry : *list) {
-    absl::optional<T> parsed_entry = entry_parser.Run(list_entry);
+    absl::optional<T> parsed_entry = entry_parser.Run(list_entry.GetDict());
     if (parsed_entry.has_value()) {
       parsed_list.push_back(std::move(*parsed_entry));
     }
diff --git a/ash/services/recording/BUILD.gn b/chromeos/ash/services/recording/BUILD.gn
similarity index 83%
rename from ash/services/recording/BUILD.gn
rename to chromeos/ash/services/recording/BUILD.gn
index 9b4cd1e8..1d965e6d 100644
--- a/ash/services/recording/BUILD.gn
+++ b/chromeos/ash/services/recording/BUILD.gn
@@ -19,8 +19,8 @@
 
   deps = [
     "//ash/constants",
-    "//ash/services/recording/public/mojom",
     "//base",
+    "//chromeos/ash/services/recording/public/mojom",
     "//media",
     "//services/audio/public/cpp",
   ]
@@ -35,9 +35,9 @@
   ]
 
   deps = [
-    "//ash/services/recording",
-    "//ash/services/recording/public/mojom",
     "//base",
+    "//chromeos/ash/services/recording",
+    "//chromeos/ash/services/recording/public/mojom",
     "//media",
   ]
 }
diff --git a/ash/services/recording/DEPS b/chromeos/ash/services/recording/DEPS
similarity index 100%
rename from ash/services/recording/DEPS
rename to chromeos/ash/services/recording/DEPS
diff --git a/ash/services/recording/DIR_METADATA b/chromeos/ash/services/recording/DIR_METADATA
similarity index 100%
rename from ash/services/recording/DIR_METADATA
rename to chromeos/ash/services/recording/DIR_METADATA
diff --git a/ash/services/recording/OWNERS b/chromeos/ash/services/recording/OWNERS
similarity index 100%
rename from ash/services/recording/OWNERS
rename to chromeos/ash/services/recording/OWNERS
diff --git a/ash/services/recording/public/mojom/BUILD.gn b/chromeos/ash/services/recording/public/mojom/BUILD.gn
similarity index 100%
rename from ash/services/recording/public/mojom/BUILD.gn
rename to chromeos/ash/services/recording/public/mojom/BUILD.gn
diff --git a/ash/services/recording/public/mojom/OWNERS b/chromeos/ash/services/recording/public/mojom/OWNERS
similarity index 100%
rename from ash/services/recording/public/mojom/OWNERS
rename to chromeos/ash/services/recording/public/mojom/OWNERS
diff --git a/ash/services/recording/public/mojom/recording_service.mojom b/chromeos/ash/services/recording/public/mojom/recording_service.mojom
similarity index 100%
rename from ash/services/recording/public/mojom/recording_service.mojom
rename to chromeos/ash/services/recording/public/mojom/recording_service.mojom
diff --git a/ash/services/recording/recording_encoder_muxer.cc b/chromeos/ash/services/recording/recording_encoder_muxer.cc
similarity index 98%
rename from ash/services/recording/recording_encoder_muxer.cc
rename to chromeos/ash/services/recording/recording_encoder_muxer.cc
index 99d2f5d..fd39c478 100644
--- a/ash/services/recording/recording_encoder_muxer.cc
+++ b/chromeos/ash/services/recording/recording_encoder_muxer.cc
@@ -2,10 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/services/recording/recording_encoder_muxer.h"
+#include "chromeos/ash/services/recording/recording_encoder_muxer.h"
 
-#include "ash/services/recording/public/mojom/recording_service.mojom.h"
-#include "ash/services/recording/recording_service_constants.h"
 #include "base/bind.h"
 #include "base/check_op.h"
 #include "base/files/file_path.h"
@@ -13,6 +11,8 @@
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string_util.h"
 #include "base/system/sys_info.h"
+#include "chromeos/ash/services/recording/public/mojom/recording_service.mojom.h"
+#include "chromeos/ash/services/recording/recording_service_constants.h"
 #include "media/base/audio_codecs.h"
 #include "media/base/video_codecs.h"
 #include "media/base/video_frame.h"
diff --git a/ash/services/recording/recording_encoder_muxer.h b/chromeos/ash/services/recording/recording_encoder_muxer.h
similarity index 97%
rename from ash/services/recording/recording_encoder_muxer.h
rename to chromeos/ash/services/recording/recording_encoder_muxer.h
index d4ec96f..41b6aee 100644
--- a/ash/services/recording/recording_encoder_muxer.h
+++ b/chromeos/ash/services/recording/recording_encoder_muxer.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_SERVICES_RECORDING_RECORDING_ENCODER_MUXER_H_
-#define ASH_SERVICES_RECORDING_RECORDING_ENCODER_MUXER_H_
+#ifndef CHROMEOS_ASH_SERVICES_RECORDING_RECORDING_ENCODER_MUXER_H_
+#define CHROMEOS_ASH_SERVICES_RECORDING_RECORDING_ENCODER_MUXER_H_
 
 #include <memory>
 
@@ -248,4 +248,4 @@
 
 }  // namespace recording
 
-#endif  // ASH_SERVICES_RECORDING_RECORDING_ENCODER_MUXER_H_
+#endif  // CHROMEOS_ASH_SERVICES_RECORDING_RECORDING_ENCODER_MUXER_H_
diff --git a/ash/services/recording/recording_service.cc b/chromeos/ash/services/recording/recording_service.cc
similarity index 98%
rename from ash/services/recording/recording_service.cc
rename to chromeos/ash/services/recording/recording_service.cc
index db786576..6d8a8ce 100644
--- a/ash/services/recording/recording_service.cc
+++ b/chromeos/ash/services/recording/recording_service.cc
@@ -2,16 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/services/recording/recording_service.h"
+#include "chromeos/ash/services/recording/recording_service.h"
 
 #include <cmath>
 #include <cstdint>
 #include <cstdlib>
 
 #include "ash/constants/ash_features.h"
-#include "ash/services/recording/recording_encoder_muxer.h"
-#include "ash/services/recording/recording_service_constants.h"
-#include "ash/services/recording/video_capture_params.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/check.h"
@@ -19,6 +16,9 @@
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
 #include "base/time/time.h"
+#include "chromeos/ash/services/recording/recording_encoder_muxer.h"
+#include "chromeos/ash/services/recording/recording_service_constants.h"
+#include "chromeos/ash/services/recording/video_capture_params.h"
 #include "media/audio/audio_device_description.h"
 #include "media/base/audio_codecs.h"
 #include "media/base/status.h"
diff --git a/ash/services/recording/recording_service.h b/chromeos/ash/services/recording/recording_service.h
similarity index 96%
rename from ash/services/recording/recording_service.h
rename to chromeos/ash/services/recording/recording_service.h
index 77b0ce6..9dfd4c9 100644
--- a/ash/services/recording/recording_service.h
+++ b/chromeos/ash/services/recording/recording_service.h
@@ -2,16 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_SERVICES_RECORDING_RECORDING_SERVICE_H_
-#define ASH_SERVICES_RECORDING_RECORDING_SERVICE_H_
+#ifndef CHROMEOS_ASH_SERVICES_RECORDING_RECORDING_SERVICE_H_
+#define CHROMEOS_ASH_SERVICES_RECORDING_RECORDING_SERVICE_H_
 
 #include <memory>
 #include <string>
 #include <utility>
 
-#include "ash/services/recording/public/mojom/recording_service.mojom.h"
-#include "ash/services/recording/recording_encoder_muxer.h"
-#include "ash/services/recording/video_capture_params.h"
 #include "base/bind.h"
 #include "base/callback_forward.h"
 #include "base/memory/scoped_refptr.h"
@@ -22,6 +19,9 @@
 #include "base/thread_annotations.h"
 #include "base/threading/sequence_bound.h"
 #include "base/threading/thread_checker.h"
+#include "chromeos/ash/services/recording/public/mojom/recording_service.mojom.h"
+#include "chromeos/ash/services/recording/recording_encoder_muxer.h"
+#include "chromeos/ash/services/recording/video_capture_params.h"
 #include "media/base/audio_bus.h"
 #include "media/base/audio_capturer_source.h"
 #include "media/base/audio_parameters.h"
@@ -264,4 +264,4 @@
 };
 
 }  // namespace recording
-#endif  // ASH_SERVICES_RECORDING_RECORDING_SERVICE_H_
+#endif  // CHROMEOS_ASH_SERVICES_RECORDING_RECORDING_SERVICE_H_
diff --git a/ash/services/recording/recording_service_constants.h b/chromeos/ash/services/recording/recording_service_constants.h
similarity index 83%
rename from ash/services/recording/recording_service_constants.h
rename to chromeos/ash/services/recording/recording_service_constants.h
index a303831e..69be7e3b 100644
--- a/ash/services/recording/recording_service_constants.h
+++ b/chromeos/ash/services/recording/recording_service_constants.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_SERVICES_RECORDING_RECORDING_SERVICE_CONSTANTS_H_
-#define ASH_SERVICES_RECORDING_RECORDING_SERVICE_CONSTANTS_H_
+#ifndef CHROMEOS_ASH_SERVICES_RECORDING_RECORDING_SERVICE_CONSTANTS_H_
+#define CHROMEOS_ASH_SERVICES_RECORDING_RECORDING_SERVICE_CONSTANTS_H_
 
 #include "base/time/time.h"
 #include "ui/gfx/color_space.h"
@@ -31,4 +31,4 @@
 
 }  // namespace recording
 
-#endif  // ASH_SERVICES_RECORDING_RECORDING_SERVICE_CONSTANTS_H_
+#endif  // CHROMEOS_ASH_SERVICES_RECORDING_RECORDING_SERVICE_CONSTANTS_H_
diff --git a/ash/services/recording/recording_service_test_api.cc b/chromeos/ash/services/recording/recording_service_test_api.cc
similarity index 97%
rename from ash/services/recording/recording_service_test_api.cc
rename to chromeos/ash/services/recording/recording_service_test_api.cc
index c13c6e1..caaa29f 100644
--- a/ash/services/recording/recording_service_test_api.cc
+++ b/chromeos/ash/services/recording/recording_service_test_api.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 "ash/services/recording/recording_service_test_api.h"
+#include "chromeos/ash/services/recording/recording_service_test_api.h"
 
 #include "base/bind.h"
 #include "base/run_loop.h"
diff --git a/ash/services/recording/recording_service_test_api.h b/chromeos/ash/services/recording/recording_service_test_api.h
similarity index 87%
rename from ash/services/recording/recording_service_test_api.h
rename to chromeos/ash/services/recording/recording_service_test_api.h
index 1635392b..409dbc22 100644
--- a/ash/services/recording/recording_service_test_api.h
+++ b/chromeos/ash/services/recording/recording_service_test_api.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_SERVICES_RECORDING_RECORDING_SERVICE_TEST_API_H_
-#define ASH_SERVICES_RECORDING_RECORDING_SERVICE_TEST_API_H_
+#ifndef CHROMEOS_ASH_SERVICES_RECORDING_RECORDING_SERVICE_TEST_API_H_
+#define CHROMEOS_ASH_SERVICES_RECORDING_RECORDING_SERVICE_TEST_API_H_
 
-#include "ash/services/recording/public/mojom/recording_service.mojom.h"
-#include "ash/services/recording/recording_service.h"
 #include "base/callback_forward.h"
 #include "base/callback_helpers.h"
+#include "chromeos/ash/services/recording/public/mojom/recording_service.mojom.h"
+#include "chromeos/ash/services/recording/recording_service.h"
 #include "media/base/video_frame.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "ui/gfx/image/image_skia.h"
@@ -66,4 +66,4 @@
 
 }  // namespace recording
 
-#endif  // ASH_SERVICES_RECORDING_RECORDING_SERVICE_TEST_API_H_
+#endif  // CHROMEOS_ASH_SERVICES_RECORDING_RECORDING_SERVICE_TEST_API_H_
diff --git a/ash/services/recording/video_capture_params.cc b/chromeos/ash/services/recording/video_capture_params.cc
similarity index 98%
rename from ash/services/recording/video_capture_params.cc
rename to chromeos/ash/services/recording/video_capture_params.cc
index 991884b..3eeb0e05 100644
--- a/ash/services/recording/video_capture_params.cc
+++ b/chromeos/ash/services/recording/video_capture_params.cc
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/services/recording/video_capture_params.h"
+#include "chromeos/ash/services/recording/video_capture_params.h"
 
-#include "ash/services/recording/recording_service_constants.h"
 #include "base/check.h"
+#include "chromeos/ash/services/recording/recording_service_constants.h"
 #include "components/viz/common/surfaces/subtree_capture_id.h"
 #include "media/base/video_types.h"
 #include "services/viz/privileged/mojom/compositing/frame_sink_video_capture.mojom.h"
diff --git a/ash/services/recording/video_capture_params.h b/chromeos/ash/services/recording/video_capture_params.h
similarity index 97%
rename from ash/services/recording/video_capture_params.h
rename to chromeos/ash/services/recording/video_capture_params.h
index 3d5cf1e..50c421c 100644
--- a/ash/services/recording/video_capture_params.h
+++ b/chromeos/ash/services/recording/video_capture_params.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_SERVICES_RECORDING_VIDEO_CAPTURE_PARAMS_H_
-#define ASH_SERVICES_RECORDING_VIDEO_CAPTURE_PARAMS_H_
+#ifndef CHROMEOS_ASH_SERVICES_RECORDING_VIDEO_CAPTURE_PARAMS_H_
+#define CHROMEOS_ASH_SERVICES_RECORDING_VIDEO_CAPTURE_PARAMS_H_
 
 #include <memory>
 
@@ -167,4 +167,4 @@
 
 }  // namespace recording
 
-#endif  // ASH_SERVICES_RECORDING_VIDEO_CAPTURE_PARAMS_H_
+#endif  // CHROMEOS_ASH_SERVICES_RECORDING_VIDEO_CAPTURE_PARAMS_H_
diff --git a/chromeos/crosapi/cpp/keystore_service_util.cc b/chromeos/crosapi/cpp/keystore_service_util.cc
index b7d1f2b..c45f1c9 100644
--- a/chromeos/crosapi/cpp/keystore_service_util.cc
+++ b/chromeos/crosapi/cpp/keystore_service_util.cc
@@ -17,49 +17,47 @@
 const char kWebCryptoNamedCurveP256[] = "P-256";
 
 // Converts a signing algorithm into a WebCrypto dictionary.
-absl::optional<base::DictionaryValue> DictionaryFromSigningAlgorithm(
+absl::optional<base::Value::Dict> DictionaryFromSigningAlgorithm(
     const crosapi::mojom::KeystoreSigningAlgorithmPtr& algorithm) {
-  base::DictionaryValue value;
+  base::Value::Dict value;
   switch (algorithm->which()) {
     case crosapi::mojom::KeystoreSigningAlgorithm::Tag::kPkcs115:
-      value.SetStringKey("name", kWebCryptoRsassaPkcs1v15);
+      value.Set("name", kWebCryptoRsassaPkcs1v15);
 
       if (!base::IsValueInRangeForNumericType<int>(
               algorithm->get_pkcs115()->modulus_length)) {
         return absl::nullopt;
       }
 
-      value.SetKey("modulusLength",
-                   base::Value(base::checked_cast<int>(
-                       algorithm->get_pkcs115()->modulus_length)));
+      value.Set("modulusLength",
+                static_cast<int>(algorithm->get_pkcs115()->modulus_length));
 
       if (!algorithm->get_pkcs115()->public_exponent) {
         return absl::nullopt;
       }
-      value.SetKey(
-          "publicExponent",
-          base::Value(algorithm->get_pkcs115()->public_exponent.value()));
-      break;
+      value.Set("publicExponent",
+                base::Value::BlobStorage(
+                    algorithm->get_pkcs115()->public_exponent.value()));
+      return value;
     case crosapi::mojom::KeystoreSigningAlgorithm::Tag::kEcdsa:
-      value.SetStringKey("name", kWebCryptoEcdsa);
-      value.SetStringKey("namedCurve", algorithm->get_ecdsa()->named_curve);
-      break;
+      value.Set("name", kWebCryptoEcdsa);
+      value.Set("namedCurve", algorithm->get_ecdsa()->named_curve);
+      return value;
     default:
       return absl::nullopt;
   }
-  return value;
 }
 
 absl::optional<crosapi::mojom::KeystoreSigningAlgorithmPtr>
-SigningAlgorithmFromDictionary(const base::DictionaryValue& dictionary) {
-  const std::string* name = dictionary.FindStringKey("name");
+SigningAlgorithmFromDictionary(const base::Value::Dict& dictionary) {
+  const std::string* name = dictionary.FindString("name");
   if (!name)
     return absl::nullopt;
 
   if (*name == kWebCryptoRsassaPkcs1v15) {
-    absl::optional<int> modulus_length = dictionary.FindIntKey("modulusLength");
+    absl::optional<int> modulus_length = dictionary.FindInt("modulusLength");
     const std::vector<uint8_t>* public_exponent =
-        dictionary.FindBlobKey("publicExponent");
+        dictionary.FindBlob("publicExponent");
     if (!modulus_length || !public_exponent)
       return absl::nullopt;
     if (!base::IsValueInRangeForNumericType<uint32_t>(modulus_length.value()))
@@ -74,7 +72,7 @@
   }
 
   if (*name == kWebCryptoEcdsa) {
-    const std::string* named_curve = dictionary.FindStringKey("namedCurve");
+    const std::string* named_curve = dictionary.FindString("namedCurve");
     if (!named_curve)
       return absl::nullopt;
     crosapi::mojom::KeystoreECDSAParamsPtr params =
diff --git a/chromeos/crosapi/cpp/keystore_service_util.h b/chromeos/crosapi/cpp/keystore_service_util.h
index ae7d320..797f250c 100644
--- a/chromeos/crosapi/cpp/keystore_service_util.h
+++ b/chromeos/crosapi/cpp/keystore_service_util.h
@@ -28,14 +28,14 @@
 // Converts a crosapi signing algorithm into a WebCrypto dictionary. Returns
 // absl::nullopt on error.
 COMPONENT_EXPORT(CROSAPI)
-absl::optional<base::DictionaryValue> DictionaryFromSigningAlgorithm(
+absl::optional<base::Value::Dict> DictionaryFromSigningAlgorithm(
     const mojom::KeystoreSigningAlgorithmPtr& algorithm);
 
 // Converts a WebCrypto dictionary into a crosapi signing algorithm. Returns
 // absl::nullopt on error.
 COMPONENT_EXPORT(CROSAPI)
 absl::optional<mojom::KeystoreSigningAlgorithmPtr>
-SigningAlgorithmFromDictionary(const base::DictionaryValue& dictionary);
+SigningAlgorithmFromDictionary(const base::Value::Dict& dictionary);
 
 // Creates the KeystorePKCS115Params variant of the KeystoreSigningAlgorithm
 // union and populates the modulus_length field with |modulus_length|.
diff --git a/chromeos/crosapi/cpp/keystore_service_util_unittest.cc b/chromeos/crosapi/cpp/keystore_service_util_unittest.cc
index b8022e9..ddec360 100644
--- a/chromeos/crosapi/cpp/keystore_service_util_unittest.cc
+++ b/chromeos/crosapi/cpp/keystore_service_util_unittest.cc
@@ -11,15 +11,15 @@
 namespace keystore_service_util {
 
 TEST(KeystoreServiceUtil, ECDSA) {
-  base::DictionaryValue value;
-  value.SetStringKey("name", kWebCryptoEcdsa);
-  value.SetStringKey("namedCurve", kWebCryptoNamedCurveP256);
+  base::Value::Dict value;
+  value.Set("name", kWebCryptoEcdsa);
+  value.Set("namedCurve", kWebCryptoNamedCurveP256);
 
   absl::optional<crosapi::mojom::KeystoreSigningAlgorithmPtr> ptr =
       SigningAlgorithmFromDictionary(value);
   ASSERT_TRUE(ptr);
 
-  absl::optional<base::DictionaryValue> value2 =
+  absl::optional<base::Value::Dict> value2 =
       DictionaryFromSigningAlgorithm(ptr.value());
   ASSERT_TRUE(value2);
 
@@ -27,20 +27,21 @@
 }
 
 TEST(KeystoreServiceUtil, PKCS) {
-  base::DictionaryValue value;
-  value.SetStringKey("name", kWebCryptoRsassaPkcs1v15);
-  value.SetKey("modulusLength", base::Value(5));
+  base::Value::Dict value;
+  value.Set("name", kWebCryptoRsassaPkcs1v15);
+  value.Set("modulusLength", 5);
 
   // Equals 65537.
   static constexpr uint8_t kDefaultPublicExponent[] = {0x01, 0x00, 0x01};
-  value.SetKey("publicExponent",
-               base::Value(base::make_span(kDefaultPublicExponent)));
+  value.Set("publicExponent",
+            base::Value::BlobStorage(std::begin(kDefaultPublicExponent),
+                                     std::end(kDefaultPublicExponent)));
 
   absl::optional<crosapi::mojom::KeystoreSigningAlgorithmPtr> ptr =
       SigningAlgorithmFromDictionary(value);
   ASSERT_TRUE(ptr);
 
-  absl::optional<base::DictionaryValue> value2 =
+  absl::optional<base::Value::Dict> value2 =
       DictionaryFromSigningAlgorithm(ptr.value());
   ASSERT_TRUE(value2);
 
diff --git a/chromeos/services/network_config/BUILD.gn b/chromeos/services/network_config/BUILD.gn
index 4480746f..a84eec0 100644
--- a/chromeos/services/network_config/BUILD.gn
+++ b/chromeos/services/network_config/BUILD.gn
@@ -30,6 +30,8 @@
 }
 
 component("in_process_instance") {
+  output_name = "network_config_in_process_instance"
+
   sources = [
     "in_process_instance.cc",
     "in_process_instance.h",
diff --git a/chromeos/services/network_health/BUILD.gn b/chromeos/services/network_health/BUILD.gn
index 82e9d254..a934c8f 100644
--- a/chromeos/services/network_health/BUILD.gn
+++ b/chromeos/services/network_health/BUILD.gn
@@ -15,6 +15,29 @@
     "//chromeos/services/network_config/public/cpp",
     "//chromeos/services/network_config/public/mojom",
     "//chromeos/services/network_health/public/mojom",
+    "//components/device_event_log",
+    "//mojo/public/cpp/bindings",
+  ]
+}
+
+component("in_process_instance") {
+  output_name = "network_health_in_process_instance"
+
+  sources = [
+    "in_process_instance.cc",
+    "in_process_instance.h",
+  ]
+
+  defines = [ "IS_IN_PROCESS_NETWORK_HEALTH_IMPL" ]
+
+  public_deps = [
+    "//chromeos/services/network_health/public/mojom",
+    "//mojo/public/cpp/bindings",
+  ]
+
+  deps = [
+    ":network_health",
+    "//chromeos/services/network_health/public/mojom",
     "//mojo/public/cpp/bindings",
   ]
 }
diff --git a/chromeos/services/network_health/in_process_instance.cc b/chromeos/services/network_health/in_process_instance.cc
new file mode 100644
index 0000000..1e69455
--- /dev/null
+++ b/chromeos/services/network_health/in_process_instance.cc
@@ -0,0 +1,17 @@
+// 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 "chromeos/services/network_health/in_process_instance.h"
+
+#include "base/no_destructor.h"
+#include "chromeos/services/network_health/network_health_service.h"
+
+namespace chromeos::network_health {
+
+NetworkHealthService* GetInProcessInstance() {
+  static base::NoDestructor<NetworkHealthService> instance;
+  return instance.get();
+}
+
+}  // namespace chromeos::network_health
diff --git a/chromeos/services/network_health/in_process_instance.h b/chromeos/services/network_health/in_process_instance.h
new file mode 100644
index 0000000..7cfc0d3
--- /dev/null
+++ b/chromeos/services/network_health/in_process_instance.h
@@ -0,0 +1,19 @@
+// 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 CHROMEOS_SERVICES_NETWORK_HEALTH_IN_PROCESS_INSTANCE_H_
+#define CHROMEOS_SERVICES_NETWORK_HEALTH_IN_PROCESS_INSTANCE_H_
+
+#include "base/component_export.h"
+
+namespace chromeos::network_health {
+
+class NetworkHealthService;
+
+COMPONENT_EXPORT(IN_PROCESS_NETWORK_HEALTH)
+NetworkHealthService* GetInProcessInstance();
+
+}  // namespace chromeos::network_health
+
+#endif  // CHROMEOS_SERVICES_NETWORK_HEALTH_IN_PROCESS_INSTANCE_H_
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index dd36057..565039d6 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -195,8 +195,6 @@
     "form_parsing/merchant_promo_code_field.h",
     "form_parsing/name_field.cc",
     "form_parsing/name_field.h",
-    "form_parsing/numeric_quantity_field.cc",
-    "form_parsing/numeric_quantity_field.h",
     "form_parsing/phone_field.cc",
     "form_parsing/phone_field.h",
     "form_parsing/price_field.cc",
@@ -843,7 +841,6 @@
     "form_parsing/iban_field_unittest.cc",
     "form_parsing/merchant_promo_code_field_unittest.cc",
     "form_parsing/name_field_unittest.cc",
-    "form_parsing/numeric_quantity_field_unittest.cc",
     "form_parsing/parsing_test_utils.cc",
     "form_parsing/parsing_test_utils.h",
     "form_parsing/phone_field_unittest.cc",
diff --git a/components/autofill/core/browser/autofill_field.cc b/components/autofill/core/browser/autofill_field.cc
index 2c24430..5db7dd7e 100644
--- a/components/autofill/core/browser/autofill_field.cc
+++ b/components/autofill/core/browser/autofill_field.cc
@@ -204,16 +204,6 @@
     // predictions get precedence over the server predictions.
     believe_server = believe_server && (heuristic_type() != IBAN_VALUE);
 
-    // The numeric quanity heuristic should get granted precedence over the
-    // server prediction since it tries to catch false-positive server
-    // predictions.
-    believe_server =
-        believe_server &&
-        !(heuristic_type() == NUMERIC_QUANTITY &&
-          server_type() != UNKNOWN_TYPE &&
-          base::FeatureList::IsEnabled(
-              features::kAutofillGivePrecedenceToNumericQuantitites));
-
     if (believe_server)
       return AutofillType(server_type());
   }
diff --git a/components/autofill/core/browser/autofill_type.cc b/components/autofill/core/browser/autofill_type.cc
index 9210bee..12ba1841 100644
--- a/components/autofill/core/browser/autofill_type.cc
+++ b/components/autofill/core/browser/autofill_type.cc
@@ -116,7 +116,6 @@
 
     case PRICE:
     case SEARCH_TERM:
-    case NUMERIC_QUANTITY:
       return FieldTypeGroup::kUnfillable;
 
     case UNKNOWN_TYPE:
diff --git a/components/autofill/core/browser/field_types.cc b/components/autofill/core/browser/field_types.cc
index bfbdf55..92392e0e 100644
--- a/components/autofill/core/browser/field_types.cc
+++ b/components/autofill/core/browser/field_types.cc
@@ -141,7 +141,6 @@
     case FIELD_WITH_DEFAULT_VALUE:
     case MERCHANT_EMAIL_SIGNUP:
     case PRICE:
-    case NUMERIC_QUANTITY:
     case SEARCH_TERM:
     case BIRTHDATE_DAY:
     case BIRTHDATE_MONTH:
@@ -294,8 +293,6 @@
       return "SEARCH_TERM";
     case PRICE:
       return "PRICE";
-    case NUMERIC_QUANTITY:
-      return "NUMERIC_QUANTITY";
     case NOT_PASSWORD:
       return "NOT_PASSWORD";
     case SINGLE_USERNAME:
diff --git a/components/autofill/core/browser/field_types.h b/components/autofill/core/browser/field_types.h
index 7c26d70d..332c19b 100644
--- a/components/autofill/core/browser/field_types.h
+++ b/components/autofill/core/browser/field_types.h
@@ -348,16 +348,11 @@
 
   // Reserved for a server-side-only use: 127
 
-  // Type of a field that asks for a numeric quantity. Not fillable by Autofill.
-  // The purpose is to ignore false positive server classification for numeric
-  // types that a prone to false-positive votes.
-  NUMERIC_QUANTITY = 128,
-
   // No new types can be added without a corresponding change to the Autofill
   // server.
   // Please update enum `AutofillServerFieldType` in
   // `tools/metrics/histogram/enums.xml` for metrics tracking.
-  MAX_VALID_FIELD_TYPE = 129,
+  MAX_VALID_FIELD_TYPE = 128,
 };
 
 enum class FieldTypeGroup {
diff --git a/components/autofill/core/browser/field_types_unittest.cc b/components/autofill/core/browser/field_types_unittest.cc
index a29050d..7b194dad 100644
--- a/components/autofill/core/browser/field_types_unittest.cc
+++ b/components/autofill/core/browser/field_types_unittest.cc
@@ -92,7 +92,6 @@
       BIRTHDATE_DAY,
       BIRTHDATE_MONTH,
       BIRTHDATE_4_DIGIT_YEAR,
-      NUMERIC_QUANTITY,
   };
   ServerFieldType kInvalidValue = static_cast<ServerFieldType>(123456);
   ASSERT_FALSE(kValidFieldTypes.count(kInvalidValue));
diff --git a/components/autofill/core/browser/form_parsing/address_field.cc b/components/autofill/core/browser/form_parsing/address_field.cc
index 1415214..6fc42efe 100644
--- a/components/autofill/core/browser/form_parsing/address_field.cc
+++ b/components/autofill/core/browser/form_parsing/address_field.cc
@@ -11,6 +11,7 @@
 #include <utility>
 
 #include "base/check.h"
+#include "base/strings/string_util.h"
 #include "components/autofill/core/browser/autofill_field.h"
 #include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
diff --git a/components/autofill/core/browser/form_parsing/form_field.cc b/components/autofill/core/browser/form_parsing/form_field.cc
index 7e89349..9a3bfe9 100644
--- a/components/autofill/core/browser/form_parsing/form_field.cc
+++ b/components/autofill/core/browser/form_parsing/form_field.cc
@@ -28,15 +28,14 @@
 #include "components/autofill/core/browser/form_parsing/iban_field.h"
 #include "components/autofill/core/browser/form_parsing/merchant_promo_code_field.h"
 #include "components/autofill/core/browser/form_parsing/name_field.h"
-#include "components/autofill/core/browser/form_parsing/numeric_quantity_field.h"
 #include "components/autofill/core/browser/form_parsing/phone_field.h"
 #include "components/autofill/core/browser/form_parsing/price_field.h"
 #include "components/autofill/core/browser/form_parsing/search_field.h"
 #include "components/autofill/core/browser/form_parsing/standalone_cvc_field.h"
 #include "components/autofill/core/browser/form_parsing/travel_field.h"
+#include "components/autofill/core/common/autocomplete_parsing_util.h"
 #include "components/autofill/core/browser/form_structure.h"
 #include "components/autofill/core/browser/logging/log_manager.h"
-#include "components/autofill/core/common/autocomplete_parsing_util.h"
 #include "components/autofill/core/common/autofill_constants.h"
 #include "components/autofill/core/common/autofill_features.h"
 #include "components/autofill/core/common/autofill_internals/log_message.h"
@@ -105,11 +104,6 @@
                         log_manager);
   }
 
-  // Numeric quantity pass.
-  ParseFormFieldsPass(NumericQuantityField::Parse, processed_fields,
-                      field_candidates, page_language, pattern_source,
-                      log_manager);
-
   // Credit card pass.
   ParseFormFieldsPass(CreditCardField::Parse, processed_fields,
                       field_candidates, page_language, pattern_source,
diff --git a/components/autofill/core/browser/form_parsing/form_field.h b/components/autofill/core/browser/form_parsing/form_field.h
index 962308ce..4d15cf3 100644
--- a/components/autofill/core/browser/form_parsing/form_field.h
+++ b/components/autofill/core/browser/form_parsing/form_field.h
@@ -105,7 +105,6 @@
   static constexpr float kBaseNameParserScore = 0.9f;
   static constexpr float kBaseMerchantPromoCodeParserScore = 0.85f;
   static constexpr float kBaseSearchParserScore = 0.8f;
-  static constexpr float kBaseNumericQuantityParserScore = 0.75f;
   static constexpr float kBaseAutocompleteParserScore = 0.05f;
 
   // Only derived classes may instantiate.
diff --git a/components/autofill/core/browser/form_parsing/form_field_unittest.cc b/components/autofill/core/browser/form_parsing/form_field_unittest.cc
index dd0be09..c3997d1 100644
--- a/components/autofill/core/browser/form_parsing/form_field_unittest.cc
+++ b/components/autofill/core/browser/form_parsing/form_field_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "components/autofill/core/browser/autofill_field.h"
 #include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
+#include "components/autofill/core/browser/form_parsing/buildflags.h"
 #include "components/autofill/core/browser/form_parsing/form_field.h"
 #include "components/autofill/core/browser/form_parsing/parsing_test_utils.h"
 #include "components/autofill/core/browser/form_structure.h"
diff --git a/components/autofill/core/browser/form_parsing/numeric_quantity_field.cc b/components/autofill/core/browser/form_parsing/numeric_quantity_field.cc
deleted file mode 100644
index 54a0592..0000000
--- a/components/autofill/core/browser/form_parsing/numeric_quantity_field.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/autofill/core/browser/form_parsing/numeric_quantity_field.h"
-
-#include "components/autofill/core/browser/autofill_field.h"
-#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
-#include "components/autofill/core/browser/form_parsing/regex_patterns.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
-
-namespace autofill {
-
-// static
-std::unique_ptr<FormField> NumericQuantityField::Parse(
-    AutofillScanner* scanner,
-    const LanguageCode& page_language,
-    PatternSource pattern_source,
-    LogManager* log_manager) {
-  AutofillField* field;
-  base::span<const MatchPatternRef> quantity_patterns =
-      GetMatchPatterns("NUMERIC_QUANTITY", page_language, pattern_source);
-
-  if (ParseFieldSpecifics(
-          scanner, kNumericQuantityRe,
-          kDefaultMatchParamsWith<
-              MatchFieldType::kNumber, MatchFieldType::kSelect,
-              MatchFieldType::kTextArea, MatchFieldType::kSearch>,
-          quantity_patterns, &field, {log_manager, "kNumericQuantityRe"})) {
-    return base::WrapUnique(new NumericQuantityField(field));
-  }
-
-  return nullptr;
-}
-
-NumericQuantityField::NumericQuantityField(const AutofillField* field)
-    : field_(field) {}
-
-void NumericQuantityField::AddClassifications(
-    FieldCandidatesMap& field_candidates) const {
-  AddClassification(field_, NUMERIC_QUANTITY, kBaseNumericQuantityParserScore,
-                    field_candidates);
-}
-
-}  // namespace autofill
diff --git a/components/autofill/core/browser/form_parsing/numeric_quantity_field.h b/components/autofill/core/browser/form_parsing/numeric_quantity_field.h
deleted file mode 100644
index d70241d..0000000
--- a/components/autofill/core/browser/form_parsing/numeric_quantity_field.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_NUMERIC_QUANTITY_FIELD_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_NUMERIC_QUANTITY_FIELD_H_
-
-#include <memory>
-
-#include "base/memory/raw_ptr.h"
-#include "components/autofill/core/browser/form_parsing/form_field.h"
-#include "components/autofill/core/common/language_code.h"
-
-namespace autofill {
-
-class AutofillField;
-class AutofillScanner;
-class LogManager;
-
-// Numeric quantities that are not eligible to be filled by Autofill.
-class NumericQuantityField : public FormField {
- public:
-  static std::unique_ptr<FormField> Parse(AutofillScanner* scanner,
-                                          const LanguageCode& page_language,
-                                          PatternSource pattern_source,
-                                          LogManager* log_manager);
-
-  NumericQuantityField(const NumericQuantityField&) = delete;
-  NumericQuantityField& operator=(const NumericQuantityField&) = delete;
-
- protected:
-  void AddClassifications(FieldCandidatesMap& field_candidates) const override;
-
- private:
-  explicit NumericQuantityField(const AutofillField* field);
-
-  raw_ptr<const AutofillField> field_;
-};
-
-}  // namespace autofill
-
-#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_NUMERIC_QUANTITY_FIELD_H_
diff --git a/components/autofill/core/browser/form_parsing/numeric_quantity_field_unittest.cc b/components/autofill/core/browser/form_parsing/numeric_quantity_field_unittest.cc
deleted file mode 100644
index dca79c6..0000000
--- a/components/autofill/core/browser/form_parsing/numeric_quantity_field_unittest.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/autofill/core/browser/form_parsing/numeric_quantity_field.h"
-
-#include "components/autofill/core/browser/form_parsing/parsing_test_utils.h"
-
-namespace autofill {
-
-class NumericQuantityFieldTest
-    : public FormFieldTestBase,
-      public testing::TestWithParam<PatternProviderFeatureState> {
- public:
-  explicit NumericQuantityFieldTest() : FormFieldTestBase(GetParam()) {}
-  NumericQuantityFieldTest(const NumericQuantityFieldTest&) = delete;
-  NumericQuantityFieldTest& operator=(const NumericQuantityFieldTest&) = delete;
-
- protected:
-  std::unique_ptr<FormField> Parse(
-      AutofillScanner* scanner,
-      const LanguageCode& page_language = LanguageCode("en")) override {
-    return NumericQuantityField::Parse(scanner, page_language,
-                                       GetActivePatternSource(),
-                                       /*log_manager=*/nullptr);
-  }
-};
-
-INSTANTIATE_TEST_SUITE_P(
-    NumericQuantityFieldTest,
-    NumericQuantityFieldTest,
-    ::testing::ValuesIn(PatternProviderFeatureState::All()));
-
-TEST_P(NumericQuantityFieldTest, ParseNumericQuantity) {
-  AddTextFormFieldData("quantity", "quantity", NUMERIC_QUANTITY);
-
-  ClassifyAndVerify(ParseResult::PARSED);
-}
-
-TEST_P(NumericQuantityFieldTest, ParseNonNumericQuantity) {
-  AddTextFormFieldData("name", "Name", UNKNOWN_TYPE);
-
-  ClassifyAndVerify(ParseResult::NOT_PARSED);
-}
-
-}  // namespace autofill
diff --git a/components/autofill/core/browser/form_parsing/resources/legacy_regex_patterns.json b/components/autofill/core/browser/form_parsing/resources/legacy_regex_patterns.json
index d5c4b67..eab373e 100644
--- a/components/autofill/core/browser/form_parsing/resources/legacy_regex_patterns.json
+++ b/components/autofill/core/browser/form_parsing/resources/legacy_regex_patterns.json
@@ -1298,18 +1298,6 @@
       }
     ]
   },
-  "NUMERIC_QUANTITY": {
-    "en": [
-      {
-        "pattern_identifier": "en_numeric_quantity_preserving",
-        "positive_pattern": "size|height|quantity|length|amount",
-        "positive_score": 0.95,
-        "negative_pattern": null,
-        "match_field_attributes": ["LABEL", "NAME"],
-        "match_field_input_types": ["TEXT", "SELECT", "TEXT_AREA", "NUMBER", "SEARCH"]
-      }
-    ]
-   },
   "PRICE": {
     "en": [
       {
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index 1a75b6b8..3864abe8 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -1007,33 +1007,6 @@
     const ServerFieldTypeSet& field_types = field->possible_types();
     DCHECK(!field_types.empty());
 
-    // For every field that has a heuristics prediction for a
-    // NUMERIC_QUANTITY, log if there was a colliding server
-    // prediction and if the NUMERIC_QUANTITY was a false-positive prediction.
-    // The latter is true when the field was correctly filled. This can
-    // only be recorded when the feature to grant precedence to
-    // NUMERIC_QUANTITY predictions is disabled.
-    if (observed_submission && field->heuristic_type() == NUMERIC_QUANTITY) {
-      bool field_has_non_empty_server_prediction =
-          field->server_type() != UNKNOWN_TYPE &&
-          field->server_type() != NO_SERVER_DATA;
-
-      // Log if there was a colliding server prediction.
-      AutofillMetrics::LogNumericQuantityCollidesWithServerPrediction(
-          field_has_non_empty_server_prediction);
-
-      // If there was a collision, log if the NUMERIC_QUANTITY was a false
-      // positive since the field was correctly filled.
-      if ((field->is_autofilled || field->previously_autofilled()) &&
-          field_has_non_empty_server_prediction &&
-          !base::FeatureList::IsEnabled(
-              features::kAutofillGivePrecedenceToNumericQuantitites)) {
-        AutofillMetrics::
-            LogAcceptedFilledFieldWithNumericQuantityHeuristicPrediction(
-                !field->previously_autofilled());
-      }
-    }
-
     if (field_types.count(EMPTY_TYPE) || field_types.count(UNKNOWN_TYPE)) {
       DCHECK_EQ(field_types.size(), 1u);
       continue;
diff --git a/components/autofill/core/browser/metrics/autofill_metrics.cc b/components/autofill/core/browser/metrics/autofill_metrics.cc
index c24d1a49..e97984e0 100644
--- a/components/autofill/core/browser/metrics/autofill_metrics.cc
+++ b/components/autofill/core/browser/metrics/autofill_metrics.cc
@@ -363,7 +363,6 @@
         case AMBIGUOUS_TYPE:
         case SEARCH_TERM:
         case PRICE:
-        case NUMERIC_QUANTITY:
         case NOT_PASSWORD:
         case SINGLE_USERNAME:
         case NOT_USERNAME:
@@ -3242,20 +3241,4 @@
   return result_suffix;
 }
 
-// // static
-void AutofillMetrics::LogNumericQuantityCollidesWithServerPrediction(
-    bool collision) {
-  base::UmaHistogramBoolean(
-      "Autofill.NumericQuantityCollidesWithServerPrediction", collision);
-}
-
-// static
-void AutofillMetrics::
-    LogAcceptedFilledFieldWithNumericQuantityHeuristicPrediction(
-        bool accepted) {
-  base::UmaHistogramBoolean(
-      "Autofill.AcceptedFilledFieldWithNumericQuantityHeuristicPrediction",
-      accepted);
-}
-
 }  // namespace autofill
diff --git a/components/autofill/core/browser/metrics/autofill_metrics.h b/components/autofill/core/browser/metrics/autofill_metrics.h
index f6140ff..3a31e41 100644
--- a/components/autofill/core/browser/metrics/autofill_metrics.h
+++ b/components/autofill/core/browser/metrics/autofill_metrics.h
@@ -1755,16 +1755,6 @@
       ServerFieldType server_type,
       ServerFieldType heuristic_types);
 
-  // Logs whether a heuristic detection for an NUMERIC_QUANTITY collides with a
-  // server prediction.
-  static void LogNumericQuantityCollidesWithServerPrediction(bool collision);
-
-  // Logs if the filling of a field was accepted even though it had a
-  // NUMERIC_QUANTITY. This metric is only emitted if the feature to grant the
-  // heuristic precedence is disabled.
-  static void LogAcceptedFilledFieldWithNumericQuantityHeuristicPrediction(
-      bool accepted);
-
  private:
   static void Log(AutocompleteEvent event);
 };
diff --git a/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc b/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
index 81f70df2..c813e22 100644
--- a/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
+++ b/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
@@ -648,78 +648,6 @@
       BucketsAre(test_case.credit_card_buckets));
 }
 
-// Test the emission of collisions between NUMERIC_QUANTITY and server
-// predictions as well as the potential false positives.
-TEST_F(AutofillMetricsTest, NumericQuantityCollision) {
-  // Those metrics are only collected when the numeric quantities are not
-  // getting precedence over server predictions.
-  base::test::ScopedFeatureList numeric_quanity_feature_list;
-  numeric_quanity_feature_list.InitAndDisableFeature(
-      features::kAutofillGivePrecedenceToNumericQuantitites);
-
-  // Set up our form data.
-  test::FormDescription form_description = {
-      .description_for_logging = "AutofilledStateFieldSource",
-      .fields = {{.server_type = NO_SERVER_DATA,
-                  .heuristic_type = NUMERIC_QUANTITY,
-                  .is_autofilled = false},
-                 // We add a second field to make sure the metrics are only
-                 // recorded for the field with the numeric quantity prediction.
-                 {.server_type = ADDRESS_HOME_LINE1,
-                  .heuristic_type = ADDRESS_HOME_LINE1,
-                  .is_autofilled = false}}};
-
-  // Helper to submit the `form` and test the expectations. `collision`
-  // indicates that there was a collision between the NUMERIC_QUANTITY
-  // prediction and a server prediction.
-  // If `autofill_used` and a `collision` exists, the histogram to
-  // track `false_positive` is checked.
-  auto SubmitAndTest = [this](const FormData& form, bool collision,
-                              bool autofill_used, bool false_positive) {
-    base::HistogramTester histogram_tester;
-    SubmitForm(form);
-    histogram_tester.ExpectUniqueSample(
-        "Autofill.NumericQuantityCollidesWithServerPrediction", collision, 1);
-    if (collision && autofill_used) {
-      histogram_tester.ExpectUniqueSample(
-          "Autofill.AcceptedFilledFieldWithNumericQuantityHeuristicPrediction",
-          false_positive, 1);
-    }
-  };
-
-  {
-    SCOPED_TRACE(
-        "No collision case - The numeric quanity does not collide with a "
-        "server prediction.");
-    FormData form = GetAndAddSeenForm(form_description);
-    SubmitAndTest(form, /*collision=*/false, /*autofill_used=*/false,
-                  /*false_positive=*/false);
-  }
-  {
-    SCOPED_TRACE("Collision, but nothing is filled.");
-    // Add a server prediction to create a collision.
-    form_description.fields[0].server_type = NAME_FIRST;
-    FormData form = GetAndAddSeenForm(form_description);
-    SubmitAndTest(form, /*collision=*/true, /*autofill_used=*/false,
-                  /*false_positive=*/false);
-  }
-  {
-    SCOPED_TRACE("Collision, the field is autofilled.");
-    form_description.fields[0].is_autofilled = true;
-    FormData form = GetAndAddSeenForm(form_description);
-    SubmitAndTest(form, /*collision=*/true, /*autofill_used=*/true,
-                  /*false_positive=*/true);
-  }
-  {
-    SCOPED_TRACE(
-        "Collision, the field is autofilled and subsequently changed.");
-    FormData form = GetAndAddSeenForm(form_description);
-    SimulateUserChangedTextField(form, form.fields[0]);
-    SubmitAndTest(form, /*collision=*/true, /*autofill_used=*/true,
-                  /*false_positive=*/false);
-  }
-}
-
 // Test that we log quality metrics appropriately.
 TEST_F(AutofillMetricsTest, QualityMetrics) {
   // Set up our form data.
diff --git a/components/autofill/core/browser/metrics/shadow_prediction_metrics_unittest.cc b/components/autofill/core/browser/metrics/shadow_prediction_metrics_unittest.cc
index b2dc979..1929b17d 100644
--- a/components/autofill/core/browser/metrics/shadow_prediction_metrics_unittest.cc
+++ b/components/autofill/core/browser/metrics/shadow_prediction_metrics_unittest.cc
@@ -96,7 +96,8 @@
   // If this test fails after adding a type, update
   // `AutofillPredictionsComparisonResult` in tools/metrics/histograms/enums.xml
   // and set `last_known_type` to the last entry in the enum.
-  constexpr ServerFieldType last_known_type = NUMERIC_QUANTITY;
+  constexpr ServerFieldType last_known_type =
+      CREDIT_CARD_STANDALONE_VERIFICATION_CODE;
   int max_comparison =
       GetShadowPrediction(last_known_type, NAME_FIRST, {NAME_LAST});
 
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index b7f68aa..abd84c5 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -63,12 +63,6 @@
              "AutofillAddressProfileSavePromptAddressVerificationSupport",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// Use the heuristic parser to detected unfillable numeric types in field labels
-// and grant the heuristic precedence over non-override server predictions.
-BASE_FEATURE(kAutofillGivePrecedenceToNumericQuantitites,
-             "AutofillGivePrecedenceToNumericQuantitites",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 // TODO(crbug.com/1135188): Remove this feature flag after the explicit save
 // prompts for address profiles is complete.
 // When enabled, address profile save problem will contain a dropdown for
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h
index 305216ad..e5b3f084 100644
--- a/components/autofill/core/common/autofill_features.h
+++ b/components/autofill/core/common/autofill_features.h
@@ -39,8 +39,6 @@
 BASE_DECLARE_FEATURE(
     kAutofillAddressProfileSavePromptAddressVerificationSupport);
 COMPONENT_EXPORT(AUTOFILL)
-BASE_DECLARE_FEATURE(kAutofillGivePrecedenceToNumericQuantitites);
-COMPONENT_EXPORT(AUTOFILL)
 BASE_DECLARE_FEATURE(kAutofillAddressProfileSavePromptNicknameSupport);
 COMPONENT_EXPORT(AUTOFILL)
 BASE_DECLARE_FEATURE(kAutofillAllowDuplicateFormSubmissions);
diff --git a/components/autofill/core/common/autofill_regex_constants.h b/components/autofill/core/common/autofill_regex_constants.h
index 3c9870b..0d71910 100644
--- a/components/autofill/core/common/autofill_regex_constants.h
+++ b/components/autofill/core/common/autofill_regex_constants.h
@@ -206,12 +206,6 @@
     u"|\\bprix\\b|\\bcoût\\b|\\bcout\\b|\\btarif\\b";  // fr-CA
 
 /////////////////////////////////////////////////////////////////////////////
-// numeric_quanitity.cc
-/////////////////////////////////////////////////////////////////////////////
-inline constexpr char16_t kNumericQuantityRe[] =
-    u"size|height|quantity|length|amount";
-
-/////////////////////////////////////////////////////////////////////////////
 // credit_card_field.cc
 /////////////////////////////////////////////////////////////////////////////
 inline constexpr char16_t kNameOnCardRe[] =
diff --git a/components/endpoint_fetcher/DIR_METADATA b/components/endpoint_fetcher/DIR_METADATA
new file mode 100644
index 0000000..676fe2a
--- /dev/null
+++ b/components/endpoint_fetcher/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>Shopping"
+}
+team_email: "chrome-shopping@google.com"
diff --git a/components/history_clusters/core/history_clusters_service_task_get_most_recent_clusters.cc b/components/history_clusters/core/history_clusters_service_task_get_most_recent_clusters.cc
index c391bcf..27f5a50 100644
--- a/components/history_clusters/core/history_clusters_service_task_get_most_recent_clusters.cc
+++ b/components/history_clusters/core/history_clusters_service_task_get_most_recent_clusters.cc
@@ -200,8 +200,8 @@
 
 void HistoryClustersServiceTaskGetMostRecentClusters::
     ReturnMostRecentPersistedClusters(base::Time exclusive_max_time) {
+  get_most_recent_persisted_clusters_start_time_ = base::TimeTicks::Now();
   if (GetConfig().persist_clusters_in_history_db && !recluster_) {
-    get_most_recent_persisted_clusters_start_time_ = base::TimeTicks::Now();
     history_service_->GetMostRecentClusters(
         begin_time_, exclusive_max_time,
         GetConfig().max_persisted_clusters_to_fetch,
diff --git a/components/messages/android/internal/java/res/layout/message_banner_view.xml b/components/messages/android/internal/java/res/layout/message_banner_view.xml
index a3469cd..ce91c89 100644
--- a/components/messages/android/internal/java/res/layout/message_banner_view.xml
+++ b/components/messages/android/internal/java/res/layout/message_banner_view.xml
@@ -93,7 +93,7 @@
         android:maxWidth="@dimen/message_primary_button_max_width"
         android:minWidth="@dimen/button_min_width"
         android:layout_width="wrap_content"
-        android:layout_height="match_parent"
+        android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
         android:visibility="gone" />
 
diff --git a/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerRenderTest.java b/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerRenderTest.java
index 1cf7641..f5479251 100644
--- a/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerRenderTest.java
+++ b/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerRenderTest.java
@@ -32,6 +32,7 @@
 import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate;
 import org.chromium.base.test.params.ParameterSet;
 import org.chromium.base.test.params.ParameterizedRunner;
+import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.Restriction;
@@ -48,6 +49,7 @@
  */
 @RunWith(ParameterizedRunner.class)
 @UseRunnerDelegate(BaseJUnit4RunnerDelegate.class)
+@Batch(Batch.UNIT_TESTS)
 public class MessageBannerRenderTest extends BlankUiTestActivityTestCase {
     @ClassParameter
     private static List<ParameterSet> sClassParams =
@@ -182,6 +184,64 @@
     @SmallTest
     @Feature({"RenderTest", "Messages"})
     @Restriction({RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+    public void testBasic_veryLongButtonText() throws Exception {
+        Activity activity = getActivity();
+        final String veryLongButtonText = "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 81 19 20 21"
+                + " 22 23 24 25 26 27 28 29 30 31 32 33 34";
+        PropertyModel model =
+                new PropertyModel.Builder(MessageBannerProperties.ALL_KEYS)
+                        .with(MessageBannerProperties.MESSAGE_IDENTIFIER,
+                                MessageIdentifier.TEST_MESSAGE)
+                        .with(MessageBannerProperties.TITLE, "Primary Title")
+                        .with(MessageBannerProperties.DESCRIPTION, "Secondary Title")
+                        .with(MessageBannerProperties.DESCRIPTION_MAX_LINES, 2)
+                        .with(MessageBannerProperties.PRIMARY_BUTTON_TEXT, veryLongButtonText)
+                        .build();
+        MessageBannerView view = (MessageBannerView) LayoutInflater.from(activity).inflate(
+                R.layout.message_banner_view, null, false);
+        PropertyModelChangeProcessor.create(model, view, MessageBannerViewBinder::bind);
+        LayoutParams params =
+                new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> { getActivity().setContentView(view, params); });
+        mRenderTestRule.render(view, "message_banner_basic_with_very_long_button_text");
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"RenderTest", "Messages"})
+    @Restriction({RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+    public void testBasic_resetPrimaryButtonText() throws Exception {
+        Activity activity = getActivity();
+        final String veryLongButtonText = "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 81 19 20 21"
+                + " 22 23 24 25 26 27 28 29 30 31 32 33 34";
+        PropertyModel model =
+                new PropertyModel.Builder(MessageBannerProperties.ALL_KEYS)
+                        .with(MessageBannerProperties.MESSAGE_IDENTIFIER,
+                                MessageIdentifier.TEST_MESSAGE)
+                        .with(MessageBannerProperties.TITLE, "Primary Title")
+                        .with(MessageBannerProperties.DESCRIPTION, "Secondary Title")
+                        .with(MessageBannerProperties.DESCRIPTION_MAX_LINES, 2)
+                        .with(MessageBannerProperties.PRIMARY_BUTTON_TEXT, veryLongButtonText)
+                        .build();
+        MessageBannerView view = (MessageBannerView) LayoutInflater.from(activity).inflate(
+                R.layout.message_banner_view, null, false);
+        PropertyModelChangeProcessor.create(model, view, MessageBannerViewBinder::bind);
+        LayoutParams params =
+                new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> { getActivity().setContentView(view, params); });
+
+        model.set(MessageBannerProperties.PRIMARY_BUTTON_TEXT, "Reset");
+        mRenderTestRule.render(view, "message_banner_basic_with_reset_primary_button_text");
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"RenderTest", "Messages"})
+    @Restriction({RESTRICTION_TYPE_NON_LOW_END_DEVICE})
     public void testLayoutAfterClearingDescription() throws Exception {
         Activity activity = getActivity();
         Drawable drawable = ApiCompatibilityUtils.getDrawable(
diff --git a/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerView.java b/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerView.java
index 43c86ca..d23e7c3 100644
--- a/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerView.java
+++ b/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerView.java
@@ -265,6 +265,26 @@
         setLayoutParams(params);
     }
 
+    /**
+     * Overriding onMeasure for set a proper height for primary button. By design, the primary
+     * button should fill all the remaining vertical space. If it includes very long text which
+     * makes its height larger than the main content (title + description), we should manually
+     * increase its height to prevent its text from being clipped.
+     */
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        mPrimaryButton.setMinHeight(0); // Reset min height for measuring.
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        int containerHeight = getMeasuredHeight();
+        int btnWidth = mPrimaryButton.getMeasuredWidth();
+        var wSpec = MeasureSpec.makeMeasureSpec(btnWidth, MeasureSpec.EXACTLY);
+        var hSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        mPrimaryButton.measure(wSpec, hSpec);
+        int measuredHeight = mPrimaryButton.getMeasuredHeight();
+        mPrimaryButton.setMinHeight(Math.max(measuredHeight, containerHeight));
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+
     private ListMenuButtonDelegate buildDelegateForSingleMenuItem() {
         final PropertyModel menuItemPropertyModel =
                 new PropertyModel.Builder(ListMenuItemProperties.ALL_KEYS)
diff --git a/components/omnibox/OWNERS b/components/omnibox/OWNERS
index 4102404e..8327650 100644
--- a/components/omnibox/OWNERS
+++ b/components/omnibox/OWNERS
@@ -7,3 +7,6 @@
 orinj@chromium.org
 tommycli@chromium.org
 yoangela@chromium.org
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/components/omnibox/browser/BUILD.gn b/components/omnibox/browser/BUILD.gn
index 4b7a105..1779ea0 100644
--- a/components/omnibox/browser/BUILD.gn
+++ b/components/omnibox/browser/BUILD.gn
@@ -7,6 +7,7 @@
 import("//components/vector_icons/vector_icons.gni")
 import("//device/vr/buildflags/buildflags.gni")
 import("//extensions/buildflags/buildflags.gni")
+import("//mojo/public/tools/bindings/mojom.gni")
 import("//testing/libfuzzer/fuzzer_test.gni")
 import("//third_party/protobuf/proto_library.gni")
 
@@ -248,6 +249,7 @@
   public_deps = [
     ":buildflags",
     ":location_bar",
+    ":omnibox",
     "//base",
     "//base:i18n",
     "//components/history/core/browser",
@@ -740,3 +742,8 @@
   ]
   seed_corpus = "fuzz_corpus_suggest"
 }
+
+mojom("omnibox") {
+  sources = [ "omnibox.mojom" ]
+  webui_module_path = "/"
+}
diff --git a/ash/services/recording/public/mojom/OWNERS b/components/omnibox/browser/OWNERS
similarity index 100%
copy from ash/services/recording/public/mojom/OWNERS
copy to components/omnibox/browser/OWNERS
diff --git a/components/omnibox/browser/actions/omnibox_pedal_concepts.h b/components/omnibox/browser/actions/omnibox_pedal_concepts.h
index c7b3bbd91..1984293e 100644
--- a/components/omnibox/browser/actions/omnibox_pedal_concepts.h
+++ b/components/omnibox/browser/actions/omnibox_pedal_concepts.h
@@ -1,26 +1,13 @@
 // 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.
-//       _____                           _                 _  _  _
-//      |  __ \                         | |               | |(_)| |
-//      | |  | |  ___      _ __    ___  | |_      ___   __| | _ | |_
-//      | |  | | / _ \    | '_ \  / _ \ | __|    / _ \ / _` || || __|
-//      | |__| || (_) |   | | | || (_) || |_    |  __/| (_| || || |_  _
-//      |_____/  \___/    |_| |_| \___/  \__|    \___| \__,_||_| \__|(_)
-// DO NOT EDIT. This file is tool-generated using pedal_processor.
 
 #ifndef COMPONENTS_OMNIBOX_BROWSER_ACTIONS_OMNIBOX_PEDAL_CONCEPTS_H_
 #define COMPONENTS_OMNIBOX_BROWSER_ACTIONS_OMNIBOX_PEDAL_CONCEPTS_H_
 
-// This value is generated during Pedal concept data processing, and written
-// to all data files as well as the source code here to ensure synchrony.
-// The runtime loaded data must match this version exactly or it won't load.
-constexpr int OMNIBOX_PEDAL_CONCEPTS_DATA_VERSION = 16535305;
-
-// Unique identifiers for Pedals, used to bind loaded data to implementations.
-// Also used in the Omnibox.SuggestionUsed.Pedal histogram. Do not remove or
-// reuse values. If any pedal types are removed from Chrome, the associated ID
-// will remain and be marked as obsolete.
+// Unique identifiers for Pedals, used in the Omnibox.SuggestionUsed.Pedal
+// histograms. Do not remove or reuse values. If any pedal types are removed
+// from Chrome, the associated ID will remain and be marked as obsolete.
 //
 // Automatically generate a corresponding Java enum:
 // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.omnibox.action
@@ -68,7 +55,6 @@
   CUSTOMIZE_SEARCH_ENGINES = 38,
   MANAGE_CHROMEOS_ACCESSIBILITY = 39,
   SET_CHROME_AS_DEFAULT_BROWSER = 40,
-  // DO NOT EDIT. See comment at top.
 
   // Last value, used to track the upper bounds when recording type histograms.
   // This intentionally does not have an assigned value to ensure that it's
diff --git a/components/omnibox/browser/actions/omnibox_pedal_provider.cc b/components/omnibox/browser/actions/omnibox_pedal_provider.cc
index d121e5f..1007dc69 100644
--- a/components/omnibox/browser/actions/omnibox_pedal_provider.cc
+++ b/components/omnibox/browser/actions/omnibox_pedal_provider.cc
@@ -151,12 +151,11 @@
 
 void OmniboxPedalProvider::Tokenize(OmniboxPedal::TokenSequence& out_tokens,
                                     const std::u16string& text) const {
-  // TODO(orinj): We may want to use FoldCase instead of ToLower here
-  //  once the JSON data is eliminated (for now it's still needed for tests).
-  //  See base/i18n/case_conversion.h for advice about unicode case handling.
-  //  FoldCase is equivalent to lower-casing for ASCII/English, but provides
-  //  more consistent (canonical) handling in other languages as well.
-  std::u16string reduced_text = base::i18n::ToLower(text);
+  // Note that FoldCase (not ToLower) is used here and elsewhere in this code.
+  // See base/i18n/case_conversion.h for advice about unicode case handling.
+  // FoldCase is equivalent to lower-casing for ASCII/English, but provides
+  // more consistent (canonical) handling in other languages as well.
+  std::u16string reduced_text = base::i18n::FoldCase(text);
   base::RemoveChars(reduced_text, kRemoveChars, &reduced_text);
   out_tokens.Clear();
   if (tokenize_characters_.empty()) {
@@ -257,10 +256,9 @@
   const std::string language_code = locale.substr(0, 2);
 
   // According to the pedals localization data, only a few languages
-  // were set to tokenize each character, so those are checked directly here
-  // to eliminate the need for JSON data. Note, zh-CN was set to tokenize
-  // each character but zh-TW was not so the full locale is checked for that
-  // exceptional case.
+  // were set to tokenize each character, so those are checked directly here.
+  // Note, zh-CN was set to tokenize each character but zh-TW was not so the
+  // full locale is checked for that exceptional case.
   if (language_code == "ja" || (language_code == "zh" && locale != "zh-TW")) {
     tokenize_characters_ = u"";
   } else {
diff --git a/components/omnibox/browser/autocomplete_match.cc b/components/omnibox/browser/autocomplete_match.cc
index 47ca6d86..b9637ef 100644
--- a/components/omnibox/browser/autocomplete_match.cc
+++ b/components/omnibox/browser/autocomplete_match.cc
@@ -1425,6 +1425,8 @@
     relevance = duplicate_match.relevance;
   }
 
+  from_previous = from_previous && duplicate_match.from_previous;
+
   // Take the |action|, if any, so that it will be presented instead of buried.
   if (!action && duplicate_match.action &&
       AutocompleteMatch::IsActionCompatibleType(type)) {
diff --git a/components/omnibox/browser/autocomplete_result.cc b/components/omnibox/browser/autocomplete_result.cc
index c5f8398..0e0b66b 100644
--- a/components/omnibox/browser/autocomplete_result.cc
+++ b/components/omnibox/browser/autocomplete_result.cc
@@ -246,10 +246,18 @@
   // suggestions. Skipping those suggestions is fine, since
   // `SetAllowedToBeDefault()` here is only intended to make
   // `allowed_to_be_default` more conservative (true -> false, not vice versa).
+  static bool prevent_default_previous_matches =
+      OmniboxFieldTrial::kPreventDefaultPreviousMatches.Get();
   for (auto& m : matches_) {
-    if (input.prevent_inline_autocomplete() && m.from_previous &&
-        m.allowed_to_be_default_match) {
+    if (!m.from_previous)
+      continue;
+    if (input.prevent_inline_autocomplete() && m.allowed_to_be_default_match) {
       m.SetAllowedToBeDefault(input);
+    } else if (prevent_default_previous_matches) {
+      // Transferred matches may no longer match the new input. E.g., when the
+      // user types 'gi' (and presses enter), don't inline (and navigate to)
+      // 'gi[oogle.com]'.
+      m.allowed_to_be_default_match = false;
     }
   }
 }
@@ -308,9 +316,15 @@
       top_match =
           base::ranges::find_if(matches_, [&](const AutocompleteMatch& match) {
             // Find a match that is a duplicate AND has the same fill_into_edit.
+            // Don't preserve suggestions that are not default-able; e.g.,
+            // typing 'xy' shouldn't preserve default 'xz.com/xy'.
+            static bool prevent_default_previous_matches =
+                OmniboxFieldTrial::kPreventDefaultPreviousMatches.Get();
             return default_match_fields == GetMatchComparisonFields(match) &&
                    preserve_default_match->fill_into_edit ==
-                       match.fill_into_edit;
+                       match.fill_into_edit &&
+                   (!prevent_default_previous_matches ||
+                    match.allowed_to_be_default_match);
           });
     }
 
diff --git a/components/omnibox/browser/base_search_provider.cc b/components/omnibox/browser/base_search_provider.cc
index 2f948fc..d116683 100644
--- a/components/omnibox/browser/base_search_provider.cc
+++ b/components/omnibox/browser/base_search_provider.cc
@@ -447,9 +447,8 @@
       suggestion.additional_query_params();
   match.search_terms_args->append_extra_query_params_from_command_line =
       append_extra_query_params_from_command_line;
-  // This is the destination URL sans assisted query stats.  This must be set
-  // so the AutocompleteController can properly de-dupe; the controller will
-  // eventually overwrite it before it reaches the user.
+  // Must be set for deduplication and navigation. AutocompleteController will
+  // ultimately overwrite this with the searchbox stats before navigation.
   match.destination_url = GURL(search_url.ReplaceSearchTerms(
       *match.search_terms_args, search_terms_data));
 
@@ -522,17 +521,17 @@
   if (result.should_prefetch())
     match.RecordAdditionalInfo(kSuggestMetadataKey, metadata);
 
-  // Try to add |match| to |map|.  If a match for this suggestion is
-  // already in |map|, replace it if |match| is more relevant.
+  // Try to add `match` to `map`.
   // NOTE: Keep this ToLower() call in sync with url_database.cc.
   MatchKey match_key(
       std::make_pair(base::i18n::ToLower(result.suggestion()),
                      match.search_terms_args->additional_query_params));
   const std::pair<MatchMap::iterator, bool> i(
-       map->insert(std::make_pair(match_key, match)));
-
-  bool should_prefetch = result.should_prefetch();
+      map->insert(std::make_pair(match_key, match)));
   if (!i.second) {
+    auto& existing_match = i.first->second;
+    // If a duplicate match is already in the map, replace it with `match` if it
+    // is more relevant.
     // NOTE: We purposefully do a direct relevance comparison here instead of
     // using AutocompleteMatch::MoreRelevant(), so that we'll prefer "items
     // added first" rather than "items alphabetically first" when the scores
@@ -541,15 +540,15 @@
     // system returns results sorted by recency, this means we'll pick the most
     // recent such result even if the precision of our relevance score is too
     // low to distinguish the two.
-    if (match.relevance > i.first->second.relevance) {
+    if (match.relevance > existing_match.relevance) {
       match.duplicate_matches.insert(match.duplicate_matches.end(),
-                                     i.first->second.duplicate_matches.begin(),
-                                     i.first->second.duplicate_matches.end());
-      i.first->second.duplicate_matches.clear();
-      match.duplicate_matches.push_back(i.first->second);
-      i.first->second = std::move(match);
+                                     existing_match.duplicate_matches.begin(),
+                                     existing_match.duplicate_matches.end());
+      existing_match.duplicate_matches.clear();
+      match.duplicate_matches.push_back(existing_match);
+      existing_match = std::move(match);
     } else {
-      if (match.keyword == i.first->second.keyword) {
+      if (match.keyword == existing_match.keyword) {
         // Old and new matches are from the same search provider. It is okay to
         // record one match's prefetch/prerender data onto a different match
         // (for the same query string) for the following reasons:
@@ -562,26 +561,27 @@
         // it thinks is sufficiently relevant that the user is likely to choose
         // it. Surely setting the prefetch/prerender bit on a match of even
         // higher relevance won't violate this assumption.
-        should_prefetch |= ShouldPrefetch(i.first->second);
-        i.first->second.RecordAdditionalInfo(kShouldPrefetchKey,
-                                             should_prefetch ? kTrue : kFalse);
-        if (should_prefetch)
-          i.first->second.RecordAdditionalInfo(kSuggestMetadataKey, metadata);
-        bool should_prerender =
-            result.should_prerender() || ShouldPrerender(i.first->second);
-        i.first->second.RecordAdditionalInfo(kShouldPrerenderKey,
-                                             should_prerender ? kTrue : kFalse);
+        const bool should_prefetch =
+            result.should_prefetch() || ShouldPrefetch(existing_match);
+        existing_match.RecordAdditionalInfo(kShouldPrefetchKey,
+                                            should_prefetch ? kTrue : kFalse);
+        if (should_prefetch) {
+          existing_match.RecordAdditionalInfo(kSuggestMetadataKey, metadata);
+        }
+        const bool should_prerender =
+            result.should_prerender() || ShouldPrerender(existing_match);
+        existing_match.RecordAdditionalInfo(kShouldPrerenderKey,
+                                            should_prerender ? kTrue : kFalse);
       }
-      i.first->second.duplicate_matches.push_back(std::move(match));
+      existing_match.duplicate_matches.push_back(std::move(match));
     }
-    // Copy over answer data from lower-ranking item, if necessary.
-    // This depends on the lower-ranking item always being added last - see
+    // Copy over answer data from lower-ranking duplicate, if necessary.
+    // This depends on the lower-ranking duplicate always being added last - see
     // use of push_back above.
-    AutocompleteMatch& more_relevant_match = i.first->second;
-    const AutocompleteMatch& less_relevant_match =
-        more_relevant_match.duplicate_matches.back();
-    if (less_relevant_match.answer && !more_relevant_match.answer) {
-      more_relevant_match.answer = less_relevant_match.answer;
+    const auto& less_relevant_duplicate_match =
+        existing_match.duplicate_matches.back();
+    if (less_relevant_duplicate_match.answer && !existing_match.answer) {
+      existing_match.answer = less_relevant_duplicate_match.answer;
     }
   }
 }
diff --git a/components/omnibox/browser/omnibox.mojom b/components/omnibox/browser/omnibox.mojom
new file mode 100644
index 0000000..874273b
--- /dev/null
+++ b/components/omnibox/browser/omnibox.mojom
@@ -0,0 +1,11 @@
+// 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.
+
+module omnibox.mojom;
+
+// Events that indicate that the user is about to navigate to a suggestion.
+enum NavigationPredictor {
+  kMouseDown = 1,           // The user pushed the mouse button down.
+  kUpOrDownArrowButton = 2  // The user pushed the down or up arrow button.
+};
diff --git a/components/omnibox/browser/omnibox_client.h b/components/omnibox/browser/omnibox_client.h
index cdf52be..b678df8 100644
--- a/components/omnibox/browser/omnibox_client.h
+++ b/components/omnibox/browser/omnibox_client.h
@@ -9,6 +9,7 @@
 
 #include "components/omnibox/browser/actions/omnibox_action.h"
 #include "components/omnibox/browser/autocomplete_provider_client.h"
+#include "components/omnibox/browser/omnibox.mojom-shared.h"
 #include "components/omnibox/browser/omnibox_navigation_observer.h"
 #include "components/omnibox/common/omnibox_focus_state.h"
 #include "third_party/skia/include/core/SkColor.h"
@@ -76,11 +77,14 @@
   // Returns the session ID of the current page.
   virtual const SessionID& GetSessionID() const = 0;
 
-  // Called when the user changes the selected |index| in the result list.
-  // |match| is the suggestion corresponding to that index. Currently
-  // experimental and only called from select omnibox implementations.
-  virtual void OnSelectedMatchChanged(size_t index,
-                                      const AutocompleteMatch& match) {}
+  // Called when the user changes the selected |index| in the result list via
+  // mouse down or arrow key down. |match| is the suggestion corresponding to
+  // that index. |navigation_predictor| represents the event indicated
+  // navigation was likely.
+  virtual void OnNavigationLikely(
+      size_t index,
+      const AutocompleteMatch& match,
+      omnibox::mojom::NavigationPredictor navigation_predictor) {}
 
   virtual bookmarks::BookmarkModel* GetBookmarkModel();
   virtual OmniboxControllerEmitter* GetOmniboxControllerEmitter();
diff --git a/components/omnibox/browser/omnibox_edit_model.cc b/components/omnibox/browser/omnibox_edit_model.cc
index e26da1f..a39dce0 100644
--- a/components/omnibox/browser/omnibox_edit_model.cc
+++ b/components/omnibox/browser/omnibox_edit_model.cc
@@ -38,6 +38,7 @@
 #include "components/omnibox/browser/history_url_provider.h"
 #include "components/omnibox/browser/keyword_provider.h"
 #include "components/omnibox/browser/location_bar_model.h"
+#include "components/omnibox/browser/omnibox.mojom-shared.h"
 #include "components/omnibox/browser/omnibox_client.h"
 #include "components/omnibox/browser/omnibox_edit_controller.h"
 #include "components/omnibox/browser/omnibox_event_global_tracker.h"
@@ -76,6 +77,7 @@
 
 using bookmarks::BookmarkModel;
 using metrics::OmniboxEventProto;
+using omnibox::mojom::NavigationPredictor;
 
 // Helpers --------------------------------------------------------------------
 
@@ -1479,6 +1481,10 @@
       RevertTemporaryTextAndPopup();
     } else {
       SetPopupSelection(next_selection);
+
+      // Inform the client that a new row is now selected via arrow key down.
+      OnNavigationLikely(next_selection.line,
+                         NavigationPredictor::kUpOrDownArrowButton);
     }
     return;
   }
@@ -1489,6 +1495,21 @@
   // open. In that case, we should force it to open immediately.
 }
 
+void OmniboxEditModel::OnNavigationLikely(
+    size_t line,
+    NavigationPredictor navigation_predictor) {
+  if (result().empty()) {
+    return;
+  }
+
+  if (line == OmniboxPopupSelection::kNoMatch) {
+    return;
+  }
+
+  client_->OnNavigationLikely(line, result().match_at(line),
+                              navigation_predictor);
+}
+
 bool OmniboxEditModel::MaybeStartQueryForPopup() {
   if (PopupIsOpen()) {
     return false;
@@ -1963,9 +1984,6 @@
 
   const AutocompleteMatch& match = result().match_at(popup_selection_.line);
 
-  // Inform the client that a new row is now selected.
-  client_->OnSelectedMatchChanged(popup_selection_.line, match);
-
   DCHECK((popup_selection_.state != OmniboxPopupSelection::KEYWORD_MODE) ||
          match.associated_keyword.get());
   if (popup_selection_.IsButtonFocused()) {
diff --git a/components/omnibox/browser/omnibox_edit_model.h b/components/omnibox/browser/omnibox_edit_model.h
index 5523c16..35c7262 100644
--- a/components/omnibox/browser/omnibox_edit_model.h
+++ b/components/omnibox/browser/omnibox_edit_model.h
@@ -20,6 +20,7 @@
 #include "components/omnibox/browser/autocomplete_controller.h"
 #include "components/omnibox/browser/autocomplete_input.h"
 #include "components/omnibox/browser/autocomplete_match.h"
+#include "components/omnibox/browser/omnibox.mojom-shared.h"
 #include "components/omnibox/browser/omnibox_controller.h"
 #include "components/omnibox/browser/omnibox_popup_selection.h"
 #include "components/omnibox/browser/omnibox_view.h"
@@ -512,6 +513,12 @@
   // Stores the image in a local data member and schedules a repaint.
   void SetPopupRichSuggestionBitmap(int result_index, const SkBitmap& bitmap);
 
+  // Called to indicate a navigation may occur based on
+  // |navigation_predictor| to the suggestion on |line|.
+  void OnNavigationLikely(
+      size_t line,
+      omnibox::mojom::NavigationPredictor navigation_predictor);
+
  protected:
   // Utility method to get current PrefService; protected instead of private
   // because it may be overridden by derived test classes.
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc
index f4bfd3d..c1980ef 100644
--- a/components/omnibox/browser/omnibox_field_trial.cc
+++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -755,6 +755,10 @@
     &omnibox::kAutocompleteStability,
     "AutocompleteStabilityDontCopyDoneProviders",
     false);
+const base::FeatureParam<bool> kPreventDefaultPreviousMatches(
+    &omnibox::kAutocompleteStability,
+    "AutocompleteStabilityPreventDefaultPreviousMatches",
+    false);
 const base::FeatureParam<bool> kAutocompleteStabilityAsyncProvidersFirst(
     &omnibox::kAutocompleteStability,
     "AutocompleteStabilityAsyncProvidersFirst",
diff --git a/components/omnibox/browser/omnibox_field_trial.h b/components/omnibox/browser/omnibox_field_trial.h
index 41057ac..93f3ee8d 100644
--- a/components/omnibox/browser/omnibox_field_trial.h
+++ b/components/omnibox/browser/omnibox_field_trial.h
@@ -503,6 +503,9 @@
 // providers whose suggestions are pending have their old matches copied over.
 extern const base::FeatureParam<bool>
     kAutocompleteStabilityDontCopyDoneProviders;
+// If enabled, transferred matches from the previous input are not allowed to
+// be default.
+extern const base::FeatureParam<bool> kPreventDefaultPreviousMatches;
 // Begin async providers before sync providers so their async requests can
 // happen in parallel. This effects only the search, history_url, document, and
 // on device head providers.
diff --git a/components/omnibox/resources/omnibox_pedal_synonyms.grd b/components/omnibox/resources/omnibox_pedal_synonyms.grd
index 8408551e..f67f74b9 100644
--- a/components/omnibox/resources/omnibox_pedal_synonyms.grd
+++ b/components/omnibox/resources/omnibox_pedal_synonyms.grd
@@ -169,11 +169,16 @@
   </translations>
 
   <release seq="1">
-    <!-- DO NOT EDIT the messages block. It is generated by pedal_processor. -->
+    <!-- These messages represent the triggering data for omnibox pedals.
+         User input is checked for the presence of words and phrases in the
+         lists below to determine whether pedals should be attached
+         to omnibox suggestions (i.e. annotated with an action button). -->
     <messages fallback_to_english="true">
+      <!-- The ignore group is special. Elements of this list are removed from input text before matching against synonym groups. Look up "stop words" for more info. -->
       <message name="IDS_OMNIBOX_PEDALS_IGNORE_GROUP" is_accessibility_with_no_ui="true" desc="The IGNORE group of common words without relevant meaning. The listed token sequences will be removed from input before checking for any Pedal matches. Context: The user is typing into the omnibox to find some setting or action, and the way to describe it isn't obvious. For example, they may be looking for chrome://settings/clearBrowserData but they type 'clear my history' or 'delete the browser data'. The Pedals system can identify the meaning of 'clear', 'delete', 'history', and 'browsing data' but 'the' and 'my' in this context are unnecessary extra words (sometimes called 'stop words'). The IGNORE group is the list of the most common words that users may type but which don't convey the necessary specific meaning for Pedals actions. Don't translate this list word for word; rather, consider and list any words that may be unnecessarily included in queries written by users who speak the target language. If a language doesn't have any such words, the list may be empty.">
         inside, within, for, how, the, an, do, in, my, on, to, a, i
       </message>
+
       <!-- Pedal #1: CLEAR_BROWSING_DATA -->
       <message name="IDS_OMNIBOX_PEDAL_SYNONYMS_CLEAR_BROWSING_DATA_ONE_REQUIRED_CLEAR_BROWSER_CACHE" is_accessibility_with_no_ui="true" desc="Whole phrases for the CLEAR_BROWSING_DATA Pedal's solitary triggering group. Context: The user is typing into the search bar to find a way to 'Clear browsing data' but the user is not sure how to describe this action. The input text is scanned for any phrases in this comma-separated list to determine whether the action button should appear. Do not translate the list 1:1 phrase for phrase. List several (~3-15) queries that users typing in the target language might search to perform this Pedal's action. Delimit each separate query phrase with a comma, including variations for the gender, plurals, etc. For other instructions, please see doc: https://docs.google.com/document/d/1cggNrwZvEbt9Hv_zMryByvgR8Vr4yal_V8Rxg1AOugw/edit">
         clear browser cache, clear history, delete cookies, erase browsing history
@@ -629,7 +634,6 @@
       <message name="IDS_OMNIBOX_PEDAL_SYNONYMS_SET_CHROME_AS_DEFAULT_BROWSER_ONE_OPTIONAL_DEFAULT_BROWSER" translateable="false" is_accessibility_with_no_ui="true" desc="Synonyms for the SET_CHROME_AS_DEFAULT_BROWSER Pedal's 'default browser' group. To trigger, exactly ONE of this group is OPTIONAL. Context: The user is typing into the omnibox to find a way to 'Set Chrome as the system's default browser in iOS settings' but the user is not sure how to describe this action. The input text is scanned for any words included in this synonym group to determine whether this concept is present in the query. Note: This string is not translated; it's used for triggering in English only.">
         default browser, google chrome, chrome google, browser, chrome
       </message>
-
     </messages>
   </release>
 </grit>
diff --git a/components/omnibox_pedal_ui_strings.grdp b/components/omnibox_pedal_ui_strings.grdp
index def7632..f1280f4 100644
--- a/components/omnibox_pedal_ui_strings.grdp
+++ b/components/omnibox_pedal_ui_strings.grdp
@@ -1,8 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!-- These messages are the user-facing UI strings for omnibox pedals. -->
+<!-- There are two kinds of UI strings here: -->
+<!--   * Visible UI labels -->
+<!--   * Invisible screen reader text for screen readers -->
 <grit-part>
-
-  <!-- DO NOT EDIT. This file is generated by pedal_processor. -->
-
   <message name="IDS_OMNIBOX_PEDAL_CLEAR_BROWSING_DATA_HINT" desc="The button text contents to suggest pedal action, CLEAR_BROWSING_DATA">
     Clear browsing data
   </message>
@@ -470,5 +471,4 @@
   <message name="IDS_ACC_OMNIBOX_PEDAL_SET_CHROME_AS_DEFAULT_BROWSER" desc="Announcement when pedal action button is focused, SET_CHROME_AS_DEFAULT_BROWSER">
     Set Chrome as default browser button, press Enter to set Chrome as the system's default browser in iOS settings
   </message>
-
 </grit-part>
diff --git a/components/payments/content/payment_method_manifest_table.cc b/components/payments/content/payment_method_manifest_table.cc
index 5b2f92c..960988b 100644
--- a/components/payments/content/payment_method_manifest_table.cc
+++ b/components/payments/content/payment_method_manifest_table.cc
@@ -101,10 +101,10 @@
 }
 
 void PaymentMethodManifestTable::RemoveExpiredData() {
-  const time_t now_date_in_seconds = base::Time::NowFromSystemTime().ToTimeT();
+  const base::Time now_date_in_seconds = base::Time::NowFromSystemTime();
   sql::Statement s(db_->GetUniqueStatement(
       "DELETE FROM payment_method_manifest WHERE expire_date < ?"));
-  s.BindInt64(0, now_date_in_seconds);
+  s.BindTime(0, now_date_in_seconds);
   s.Run();
 }
 
@@ -114,8 +114,8 @@
   sql::Statement s(db_->GetUniqueStatement(
       "DELETE FROM secure_payment_confirmation_instrument WHERE (date_created "
       ">= ? AND date_created < ?) OR (date_created = 0)"));
-  s.BindInt64(0, begin.ToDeltaSinceWindowsEpoch().InMicroseconds());
-  s.BindInt64(1, end.ToDeltaSinceWindowsEpoch().InMicroseconds());
+  s.BindTime(0, begin);
+  s.BindTime(1, end);
   return s.Run();
 }
 
@@ -136,12 +136,12 @@
       db_->GetUniqueStatement("INSERT INTO payment_method_manifest "
                               "(expire_date, method_name, web_app_id) "
                               "VALUES (?, ?, ?)"));
-  const time_t expire_date_in_seconds =
-      base::Time::NowFromSystemTime().ToTimeT() +
-      PAYMENT_METHOD_MANIFEST_VALID_TIME_IN_SECONDS;
+  const base::Time expire_date =
+      base::Time::FromTimeT(base::Time::NowFromSystemTime().ToTimeT() +
+                            PAYMENT_METHOD_MANIFEST_VALID_TIME_IN_SECONDS);
   for (const auto& id : web_app_ids) {
     int index = 0;
-    s2.BindInt64(index++, expire_date_in_seconds);
+    s2.BindTime(index++, expire_date);
     s2.BindString(index++, payment_method);
     s2.BindString(index, id);
     if (!s2.Run())
@@ -230,8 +230,7 @@
     s3.BindBlob(index++, credential.user_id);
     s3.BindString(index++, std::string());
     s3.BindBlob(index++, std::vector<uint8_t>());
-    s3.BindInt64(index++,
-                 base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds());
+    s3.BindTime(index++, base::Time::Now());
 
     if (!s3.Run())
       return false;
diff --git a/components/payments/content/web_app_manifest_section_table.cc b/components/payments/content/web_app_manifest_section_table.cc
index b372a3de..6506fd09 100644
--- a/components/payments/content/web_app_manifest_section_table.cc
+++ b/components/payments/content/web_app_manifest_section_table.cc
@@ -102,10 +102,10 @@
 }
 
 void WebAppManifestSectionTable::RemoveExpiredData() {
-  const time_t now_date_in_seconds = base::Time::NowFromSystemTime().ToTimeT();
+  const base::Time now = base::Time::NowFromSystemTime();
   sql::Statement s(db_->GetUniqueStatement(
       "DELETE FROM web_app_manifest_section WHERE expire_date < ? "));
-  s.BindInt64(0, now_date_in_seconds);
+  s.BindTime(0, now);
   s.Run();
 }
 
@@ -130,12 +130,12 @@
       db_->GetUniqueStatement("INSERT INTO web_app_manifest_section "
                               "(expire_date, id, min_version, fingerprints) "
                               "VALUES (?, ?, ?, ?)"));
-  const time_t expire_date_in_seconds =
-      base::Time::NowFromSystemTime().ToTimeT() +
-      WEB_APP_MANIFEST_VALID_TIME_IN_SECONDS;
+  const base::Time expire_date =
+      base::Time::FromTimeT(base::Time::NowFromSystemTime().ToTimeT() +
+                            WEB_APP_MANIFEST_VALID_TIME_IN_SECONDS);
   for (const auto& section : manifest) {
     int index = 0;
-    s2.BindInt64(index++, expire_date_in_seconds);
+    s2.BindTime(index++, expire_date);
     s2.BindString(index++, section.id);
     s2.BindInt64(index++, section.min_version);
     std::unique_ptr<std::vector<uint8_t>> serialized_fingerprints =
diff --git a/components/saved_tab_groups/saved_tab_group.cc b/components/saved_tab_groups/saved_tab_group.cc
index ca7e742..bab2cfb 100644
--- a/components/saved_tab_groups/saved_tab_group.cc
+++ b/components/saved_tab_groups/saved_tab_group.cc
@@ -9,7 +9,9 @@
 
 #include "base/guid.h"
 #include "base/notreached.h"
+#include "base/ranges/algorithm.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
 #include "components/saved_tab_groups/saved_tab_group_tab.h"
 #include "components/sync/protocol/saved_tab_group_specifics.pb.h"
 #include "components/tab_groups/tab_group_color.h"
@@ -23,12 +25,12 @@
     const tab_groups::TabGroupColorId& color,
     const std::vector<SavedTabGroupTab>& urls,
     absl::optional<base::GUID> saved_guid,
-    absl::optional<tab_groups::TabGroupId> tab_group_id,
+    absl::optional<tab_groups::TabGroupId> local_group_id,
     absl::optional<base::Time> creation_time_windows_epoch_micros,
     absl::optional<base::Time> update_time_windows_epoch_micros)
     : saved_guid_(saved_guid.has_value() ? saved_guid.value()
                                          : base::GUID::GenerateRandomV4()),
-      tab_group_id_(tab_group_id),
+      local_group_id_(local_group_id),
       title_(title),
       color_(color),
       saved_tabs_(urls),
@@ -45,6 +47,135 @@
 
 SavedTabGroup::~SavedTabGroup() = default;
 
+absl::optional<SavedTabGroupTab> SavedTabGroup::GetTab(
+    const base::GUID& tab_id) {
+  absl::optional<int> index = GetIndexOfTab(tab_id);
+  if (!index.has_value())
+    return absl::nullopt;
+
+  return saved_tabs()[index.value()];
+}
+
+bool SavedTabGroup::ContainsTab(const base::GUID& tab_id) const {
+  absl::optional<int> index = GetIndexOfTab(tab_id);
+  return index.has_value();
+}
+
+absl::optional<int> SavedTabGroup::GetIndexOfTab(
+    const base::GUID& tab_id) const {
+  auto it = base::ranges::find_if(
+      saved_tabs(),
+      [tab_id](const SavedTabGroupTab& tab) { return tab.guid() == tab_id; });
+  if (it != saved_tabs().end())
+    return it - saved_tabs().begin();
+  return absl::nullopt;
+}
+
+SavedTabGroup& SavedTabGroup::SetTitle(std::u16string title) {
+  title_ = title;
+  SetUpdateTimeWindowsEpochMicros(base::Time::Now());
+  return *this;
+}
+
+SavedTabGroup& SavedTabGroup::SetColor(tab_groups::TabGroupColorId color) {
+  color_ = color;
+  SetUpdateTimeWindowsEpochMicros(base::Time::Now());
+  return *this;
+}
+
+SavedTabGroup& SavedTabGroup::SetLocalGroupId(
+    absl::optional<tab_groups::TabGroupId> tab_group_id) {
+  local_group_id_ = tab_group_id;
+  SetUpdateTimeWindowsEpochMicros(base::Time::Now());
+  return *this;
+}
+
+SavedTabGroup& SavedTabGroup::SetUpdateTimeWindowsEpochMicros(
+    base::Time update_time_windows_epoch_micros) {
+  update_time_windows_epoch_micros_ = update_time_windows_epoch_micros;
+  return *this;
+}
+
+SavedTabGroup& SavedTabGroup::AddTab(size_t index, SavedTabGroupTab tab) {
+  CHECK_GE(index, 0u);
+  CHECK_LE(index, saved_tabs_.size());
+  CHECK(!ContainsTab(tab.guid()));
+  saved_tabs_.emplace(saved_tabs_.begin() + index, std::move(tab));
+  SetUpdateTimeWindowsEpochMicros(base::Time::Now());
+  return *this;
+}
+
+SavedTabGroup& SavedTabGroup::RemoveTab(const base::GUID& tab_id) {
+  absl::optional<size_t> index = GetIndexOfTab(tab_id);
+  CHECK(index.has_value());
+  CHECK_GE(index.value(), 0u);
+  CHECK_LT(index.value(), saved_tabs_.size());
+  saved_tabs_.erase(saved_tabs_.begin() + index.value());
+  SetUpdateTimeWindowsEpochMicros(base::Time::Now());
+  return *this;
+}
+
+SavedTabGroup& SavedTabGroup::ReplaceTabAt(const base::GUID& tab_id,
+                                           SavedTabGroupTab tab) {
+  absl::optional<size_t> index = GetIndexOfTab(tab_id);
+  CHECK(index.has_value());
+  CHECK_GE(index.value(), 0u);
+  CHECK_LT(index.value(), saved_tabs_.size());
+  CHECK(!ContainsTab(tab.guid()));
+  saved_tabs_.erase(saved_tabs_.begin() + index.value());
+  saved_tabs_.insert(saved_tabs_.begin() + index.value(), std::move(tab));
+  SetUpdateTimeWindowsEpochMicros(base::Time::Now());
+  return *this;
+}
+
+SavedTabGroup& SavedTabGroup::MoveTab(const base::GUID& tab_id,
+                                      size_t new_index) {
+  absl::optional<size_t> curr_index = GetIndexOfTab(tab_id);
+  CHECK(curr_index.has_value());
+  CHECK_GE(curr_index.value(), 0u);
+  CHECK_LT(curr_index.value(), saved_tabs_.size());
+  CHECK_GE(new_index, 0u);
+  CHECK_LT(new_index, saved_tabs_.size());
+
+  if (curr_index > new_index) {
+    std::rotate(saved_tabs_.begin() + new_index,
+                saved_tabs_.begin() + curr_index.value(),
+                saved_tabs_.begin() + curr_index.value() + 1);
+  } else if (curr_index < new_index) {
+    std::rotate(
+        saved_tabs_.rbegin() + ((saved_tabs_.size() - 1) - new_index),
+        saved_tabs_.rbegin() + ((saved_tabs_.size() - 1) - curr_index.value()),
+        saved_tabs_.rbegin() + ((saved_tabs_.size() - 1) - curr_index.value()) +
+            1);
+  }
+  SetUpdateTimeWindowsEpochMicros(base::Time::Now());
+  return *this;
+}
+
+bool SavedTabGroup::ShouldMergeGroup(
+    sync_pb::SavedTabGroupSpecifics* sync_specific) {
+  bool sync_update_is_latest =
+      sync_specific->update_time_windows_epoch_micros() >=
+      update_time_windows_epoch_micros()
+          .ToDeltaSinceWindowsEpoch()
+          .InMicroseconds();
+  // TODO(dljames): crbug/1371953 - Investigate if we should consider the
+  // creation time.
+  return sync_update_is_latest;
+}
+
+std::unique_ptr<sync_pb::SavedTabGroupSpecifics> SavedTabGroup::MergeGroup(
+    std::unique_ptr<sync_pb::SavedTabGroupSpecifics> sync_specific) {
+  if (ShouldMergeGroup(sync_specific.get())) {
+    SetTitle(base::UTF8ToUTF16(sync_specific->group().title()));
+    SetColor(SyncColorToTabGroupColor(sync_specific->group().color()));
+    SetUpdateTimeWindowsEpochMicros(base::Time::FromDeltaSinceWindowsEpoch(
+        base::Microseconds(sync_specific->update_time_windows_epoch_micros())));
+  }
+
+  return ToSpecifics();
+}
+
 // static
 SavedTabGroup SavedTabGroup::FromSpecifics(
     const sync_pb::SavedTabGroupSpecifics& specific) {
@@ -62,7 +193,8 @@
                        update_time);
 }
 
-std::unique_ptr<sync_pb::SavedTabGroupSpecifics> SavedTabGroup::ToSpecifics() {
+std::unique_ptr<sync_pb::SavedTabGroupSpecifics> SavedTabGroup::ToSpecifics()
+    const {
   std::unique_ptr<sync_pb::SavedTabGroupSpecifics> pb_specific =
       std::make_unique<sync_pb::SavedTabGroupSpecifics>();
   pb_specific->set_guid(saved_guid().AsLowercaseString());
diff --git a/components/saved_tab_groups/saved_tab_group.h b/components/saved_tab_groups/saved_tab_group.h
index 7b42a1f1..d09b70b3 100644
--- a/components/saved_tab_groups/saved_tab_group.h
+++ b/components/saved_tab_groups/saved_tab_group.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_SAVED_TAB_GROUPS_SAVED_TAB_GROUP_H_
 #define COMPONENTS_SAVED_TAB_GROUPS_SAVED_TAB_GROUP_H_
 
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -28,7 +29,7 @@
       const tab_groups::TabGroupColorId& color,
       const std::vector<SavedTabGroupTab>& urls,
       absl::optional<base::GUID> saved_guid = absl::nullopt,
-      absl::optional<tab_groups::TabGroupId> tab_group_id = absl::nullopt,
+      absl::optional<tab_groups::TabGroupId> local_group_id = absl::nullopt,
       absl::optional<base::Time> creation_time_windows_epoch_micros =
           absl::nullopt,
       absl::optional<base::Time> update_time_windows_epoch_micros =
@@ -38,8 +39,8 @@
 
   // Metadata accessors.
   const base::GUID& saved_guid() const { return saved_guid_; }
-  const absl::optional<tab_groups::TabGroupId>& tab_group_id() const {
-    return tab_group_id_;
+  const absl::optional<tab_groups::TabGroupId>& local_group_id() const {
+    return local_group_id_;
   }
   const base::Time& creation_time_windows_epoch_micros() const {
     return creation_time_windows_epoch_micros_;
@@ -52,21 +53,46 @@
   const std::vector<SavedTabGroupTab>& saved_tabs() const {
     return saved_tabs_;
   }
+  std::vector<SavedTabGroupTab>& saved_tabs() { return saved_tabs_; }
+  absl::optional<SavedTabGroupTab> GetTab(const base::GUID& tab_id);
+  // Returns the index for `tab_id` in `saved_tabs_` if it exists. Otherwise,
+  // returns absl::nullopt.
+  absl::optional<int> GetIndexOfTab(const base::GUID& tab_id) const;
+
+  // Returns true if the `tab_id` was found in `saved_tabs_`.
+  bool ContainsTab(const base::GUID& tab_id) const;
 
   // Metadata mutators.
-  SavedTabGroup& SetTitle(std::u16string title) {
-    title_ = title;
-    return *this;
-  }
-  SavedTabGroup& SetColor(tab_groups::TabGroupColorId color) {
-    color_ = color;
-    return *this;
-  }
+  SavedTabGroup& SetTitle(std::u16string title);
+  SavedTabGroup& SetColor(tab_groups::TabGroupColorId color);
   SavedTabGroup& SetLocalGroupId(
-      absl::optional<tab_groups::TabGroupId> tab_group_id) {
-    tab_group_id_ = tab_group_id;
-    return *this;
-  }
+      absl::optional<tab_groups::TabGroupId> tab_group_id);
+  SavedTabGroup& SetUpdateTimeWindowsEpochMicros(
+      base::Time update_time_windows_epoch_micros);
+
+  // Tab mutators.
+  // Adds `tab` to `saved_tabs_` at the specified `index` unless the added tab
+  // already exists. In this case we CHECK.
+  SavedTabGroup& AddTab(size_t index, SavedTabGroupTab tab);
+  // Removes the tab denoted by `tab_id` from `saved_tabs_`. This function will
+  // remove the last tab: crbug/1371959.
+  SavedTabGroup& RemoveTab(const base::GUID& tab_id);
+  // Replaces that tab denoted by `tab_id` with value of `tab` unless the
+  // replacement tab already exists. In this case we CHECK.
+  SavedTabGroup& ReplaceTabAt(const base::GUID& tab_id, SavedTabGroupTab tab);
+  // Moves the tab denoted by `tab_id` from its current index to the
+  // `new_index`.
+  SavedTabGroup& MoveTab(const base::GUID& tab_id, size_t new_index);
+
+  // Merges this groups data with a specific from sync and returns the newly
+  // merged specific. Side effect: Updates the values of this group.
+  std::unique_ptr<sync_pb::SavedTabGroupSpecifics> MergeGroup(
+      std::unique_ptr<sync_pb::SavedTabGroupSpecifics> sync_specific);
+
+  // We should merge a group if one of the following is true:
+  // 1. The data from `sync_specific` has the most recent (larger) update time.
+  // 2. The `sync_specific` has the oldest (smallest) creation time.
+  bool ShouldMergeGroup(sync_pb::SavedTabGroupSpecifics* sync_specific);
 
   // Converts a `SavedTabGroupSpecifics` retrieved from sync into a
   // `SavedTabGroupTab`.
@@ -74,7 +100,7 @@
       const sync_pb::SavedTabGroupSpecifics& specific);
 
   // Converts a `SavedTabGroupTab` into a `SavedTabGroupSpecifics` for sync.
-  std::unique_ptr<sync_pb::SavedTabGroupSpecifics> ToSpecifics();
+  std::unique_ptr<sync_pb::SavedTabGroupSpecifics> ToSpecifics() const;
 
   // Converts tab group color ids into the sync data type for saved tab group
   // colors.
@@ -92,7 +118,7 @@
   // The ID of the tab group in the tab strip which is associated with the saved
   // tab group object. This can be null if the saved tab group is not in any tab
   // strip.
-  absl::optional<tab_groups::TabGroupId> tab_group_id_;
+  absl::optional<tab_groups::TabGroupId> local_group_id_;
 
   // The title of the saved tab group.
   std::u16string title_;
diff --git a/components/saved_tab_groups/saved_tab_group_model.cc b/components/saved_tab_groups/saved_tab_group_model.cc
index 8ff3c323..e50376e 100644
--- a/components/saved_tab_groups/saved_tab_group_model.cc
+++ b/components/saved_tab_groups/saved_tab_group_model.cc
@@ -22,7 +22,7 @@
 
 int SavedTabGroupModel::GetIndexOf(tab_groups::TabGroupId tab_group_id) const {
   for (size_t i = 0; i < saved_tab_groups_.size(); i++)
-    if (saved_tab_groups_[i].tab_group_id() == tab_group_id)
+    if (saved_tab_groups_[i].local_group_id() == tab_group_id)
       return i;
 
   return -1;
diff --git a/components/saved_tab_groups/saved_tab_group_model_unittest.cc b/components/saved_tab_groups/saved_tab_group_model_unittest.cc
index 5c499cb..4c619c8 100644
--- a/components/saved_tab_groups/saved_tab_group_model_unittest.cc
+++ b/components/saved_tab_groups/saved_tab_group_model_unittest.cc
@@ -357,7 +357,7 @@
   ASSERT_GE(index, 0);
 
   SavedTabGroup received_group = retrieved_group_[index];
-  EXPECT_EQ(group_4.tab_group_id(), received_group.tab_group_id());
+  EXPECT_EQ(group_4.local_group_id(), received_group.local_group_id());
   EXPECT_EQ(group_4.title(), received_group.title());
   EXPECT_EQ(group_4.color(), received_group.color());
   CompareSavedTabGroupTabs(group_4.saved_tabs(), received_group.saved_tabs());
@@ -376,7 +376,7 @@
   ASSERT_GE(index, 0);
 
   SavedTabGroup received_group = retrieved_group_[index];
-  EXPECT_EQ(group_4.tab_group_id(), received_group.tab_group_id());
+  EXPECT_EQ(group_4.local_group_id(), received_group.local_group_id());
   EXPECT_EQ(group_4.title(), received_group.title());
   EXPECT_EQ(group_4.color(), received_group.color());
   CompareSavedTabGroupTabs(group_4.saved_tabs(), received_group.saved_tabs());
@@ -408,7 +408,7 @@
   ASSERT_GE(index, 0);
 
   SavedTabGroup received_group = retrieved_group_[index];
-  EXPECT_EQ(group_4.tab_group_id(), received_group.tab_group_id());
+  EXPECT_EQ(group_4.local_group_id(), received_group.local_group_id());
   EXPECT_EQ(new_title, received_group.title());
   EXPECT_EQ(new_color, received_group.color());
   CompareSavedTabGroupTabs(group_4.saved_tabs(), received_group.saved_tabs());
@@ -429,7 +429,7 @@
   // Expect the saved group that calls update is the one that was removed from
   // the tabstrip.
   saved_tab_group_model_->OnGroupClosedInTabStrip(
-      group_4.tab_group_id().value());
+      group_4.local_group_id().value());
   EXPECT_EQ(index, retrieved_index_);
 
   // Expect the removal of group_4 from the tabstrip makes GetIndexOf not return
diff --git a/components/saved_tab_groups/saved_tab_group_proto_conversion_unittest.cc b/components/saved_tab_groups/saved_tab_group_proto_conversion_unittest.cc
index 8ae2f05f..310bbf2 100644
--- a/components/saved_tab_groups/saved_tab_group_proto_conversion_unittest.cc
+++ b/components/saved_tab_groups/saved_tab_group_proto_conversion_unittest.cc
@@ -160,3 +160,63 @@
   pb_specific->clear_tab();
   pb_specific_2->clear_tab();
 }
+
+// Verifies that merging 2 group objects (1 Sync, 1 SavedTabGroup) merges the
+// most recently updated object correctly.
+TEST_F(SavedTabGroupConversionTest, MergedGroupHoldsCorrectData) {
+  // Create a group.
+  const base::Time old_time = base::Time::Now();
+  const std::u16string& title = u"Test title";
+  const tab_groups::TabGroupColorId& color = tab_groups::TabGroupColorId::kBlue;
+  absl::optional<base::GUID> saved_guid = base::GUID::GenerateRandomV4();
+  absl::optional<base::Time> creation_time_windows_epoch_micros = time_;
+  absl::optional<base::Time> update_time_windows_epoch_micros = time_;
+  SavedTabGroup group1(title, color, {}, saved_guid, absl::nullopt,
+                       creation_time_windows_epoch_micros,
+                       update_time_windows_epoch_micros);
+
+  // Create a new group with the same data and update it. Calling set functions
+  // should internally update update_time_windows_epoch_micros.
+  SavedTabGroup group2 = SavedTabGroup::FromSpecifics(*group1.ToSpecifics());
+  group2.SetColor(tab_groups::TabGroupColorId::kGreen);
+  group2.SetTitle(u"New Title");
+
+  // Expect that group2 is a valid group to merge with and that group1 hold the
+  // same data after the merge.
+  EXPECT_TRUE(group1.ShouldMergeGroup(group2.ToSpecifics().get()));
+  group1.MergeGroup(group2.ToSpecifics());
+  CompareGroups(group1, group2);
+
+  // Expect that group2 is not a valid group to merge. No merging should be
+  // done.
+  group1.SetColor(tab_groups::TabGroupColorId::kOrange);
+  group1.SetTitle(u"Another title");
+  group2.SetUpdateTimeWindowsEpochMicros(old_time);
+  EXPECT_FALSE(group1.ShouldMergeGroup(group2.ToSpecifics().get()));
+}
+
+// Verifies that merging 2 tab objects (1 Sync, 1 SavedTabGroupTab)
+TEST_F(SavedTabGroupConversionTest, MergedTabHoldsCorrectData) {
+  // Create a tab.
+  const base::Time old_time = base::Time::Now();
+  base::GUID saved_guid = base::GUID::GenerateRandomV4();
+  SavedTabGroupTab tab1(GURL("Test url"), saved_guid);
+
+  // Create a new group with the same data and update it. Calling set functions
+  // should internally update update_time_windows_epoch_micros.
+  SavedTabGroupTab tab2 = SavedTabGroupTab::FromSpecifics(*tab1.ToSpecifics());
+  tab2.SetURL(GURL("new url"));
+  tab2.SetTitle(u"New Title");
+
+  // Expect that tab2 is a valid group to merge with and that the tab1 holds the
+  // same data after the merge.
+  EXPECT_TRUE(tab1.ShouldMergeTab(tab2.ToSpecifics().get()));
+  tab1.MergeTab(tab2.ToSpecifics());
+  CompareTabs(tab1, tab2);
+
+  // Expect that tab2 is not a valid group to merge. No merging should be done.
+  tab1.SetTitle(u"A title");
+  tab1.SetURL(GURL("Another url"));
+  tab2.SetUpdateTimeWindowsEpochMicros(old_time);
+  EXPECT_FALSE(tab1.ShouldMergeTab(tab2.ToSpecifics().get()));
+}
diff --git a/components/saved_tab_groups/saved_tab_group_tab.cc b/components/saved_tab_groups/saved_tab_group_tab.cc
index bdcac46..4aaa0e7b 100644
--- a/components/saved_tab_groups/saved_tab_group_tab.cc
+++ b/components/saved_tab_groups/saved_tab_group_tab.cc
@@ -32,6 +32,27 @@
 SavedTabGroupTab::SavedTabGroupTab(const SavedTabGroupTab& other) = default;
 SavedTabGroupTab::~SavedTabGroupTab() = default;
 
+bool SavedTabGroupTab::ShouldMergeTab(
+    sync_pb::SavedTabGroupSpecifics* sync_specific) {
+  bool sync_update_is_latest =
+      sync_specific->update_time_windows_epoch_micros() >=
+      update_time_windows_epoch_micros()
+          .ToDeltaSinceWindowsEpoch()
+          .InMicroseconds();
+  return sync_update_is_latest;
+}
+
+std::unique_ptr<sync_pb::SavedTabGroupSpecifics> SavedTabGroupTab::MergeTab(
+    std::unique_ptr<sync_pb::SavedTabGroupSpecifics> sync_specific) {
+  if (ShouldMergeTab(sync_specific.get())) {
+    SetURL(GURL(sync_specific->tab().url()));
+    SetUpdateTimeWindowsEpochMicros(base::Time::FromDeltaSinceWindowsEpoch(
+        base::Microseconds(sync_specific->update_time_windows_epoch_micros())));
+  }
+
+  return ToSpecifics();
+}
+
 // static
 SavedTabGroupTab SavedTabGroupTab::FromSpecifics(
     const sync_pb::SavedTabGroupSpecifics& specific) {
@@ -49,8 +70,8 @@
                           update_time);
 }
 
-std::unique_ptr<sync_pb::SavedTabGroupSpecifics>
-SavedTabGroupTab::ToSpecifics() {
+std::unique_ptr<sync_pb::SavedTabGroupSpecifics> SavedTabGroupTab::ToSpecifics()
+    const {
   std::unique_ptr<sync_pb::SavedTabGroupSpecifics> pb_specific =
       std::make_unique<sync_pb::SavedTabGroupSpecifics>();
   pb_specific->set_guid(guid().AsLowercaseString());
diff --git a/components/saved_tab_groups/saved_tab_group_tab.h b/components/saved_tab_groups/saved_tab_group_tab.h
index f2691b6..97a53c9 100644
--- a/components/saved_tab_groups/saved_tab_group_tab.h
+++ b/components/saved_tab_groups/saved_tab_group_tab.h
@@ -53,20 +53,39 @@
   // Mutators.
   SavedTabGroupTab& SetSavedTabGroup(SavedTabGroup* saved_tab_group) {
     saved_tab_group_ = saved_tab_group;
+    SetUpdateTimeWindowsEpochMicros(base::Time::Now());
     return *this;
   }
   SavedTabGroupTab& SetURL(GURL url) {
     url_ = url;
+    SetUpdateTimeWindowsEpochMicros(base::Time::Now());
     return *this;
   }
   SavedTabGroupTab& SetTitle(std::u16string title) {
     title_ = title;
+    SetUpdateTimeWindowsEpochMicros(base::Time::Now());
     return *this;
   }
   SavedTabGroupTab& SetFavicon(absl::optional<gfx::Image> favicon) {
     favicon_ = favicon;
+    SetUpdateTimeWindowsEpochMicros(base::Time::Now());
     return *this;
   }
+  SavedTabGroupTab& SetUpdateTimeWindowsEpochMicros(
+      base::Time update_time_windows_epoch_micros) {
+    update_time_windows_epoch_micros_ = update_time_windows_epoch_micros;
+    return *this;
+  }
+
+  // Merges this tabs data with a specific from sync and returns the newly
+  // merged specific. Side effect: Updates the values in the tab.
+  std::unique_ptr<sync_pb::SavedTabGroupSpecifics> MergeTab(
+      std::unique_ptr<sync_pb::SavedTabGroupSpecifics> sync_specific);
+
+  // We should merge a tab if one of the following is true:
+  // 1. The data from `sync_specific` has the most recent (larger) update time.
+  // 2. The `sync_specific` has the oldest (smallest) creation time.
+  bool ShouldMergeTab(sync_pb::SavedTabGroupSpecifics* sync_specific);
 
   // Converts a `SavedTabGroupSpecifics` retrieved from sync into a
   // `SavedTabGroupTab`.
@@ -74,7 +93,7 @@
       const sync_pb::SavedTabGroupSpecifics& specific);
 
   // Converts this `SavedTabGroupTab` into a `SavedTabGroupSpecifics` for sync.
-  std::unique_ptr<sync_pb::SavedTabGroupSpecifics> ToSpecifics();
+  std::unique_ptr<sync_pb::SavedTabGroupSpecifics> ToSpecifics() const;
 
  private:
   // The ID used to represent the tab in sync.
diff --git a/components/search_engines/template_url_service.cc b/components/search_engines/template_url_service.cc
index 367a327..536abb06 100644
--- a/components/search_engines/template_url_service.cc
+++ b/components/search_engines/template_url_service.cc
@@ -676,6 +676,7 @@
   std::string histogram_name = kKeywordModeUsageByEngineTypeHistogramName;
   if (is_active) {
     data.is_active = TemplateURLData::ActiveStatus::kTrue;
+    data.safe_for_autoreplace = false;
     histogram_name.append(".Activated");
   } else {
     data.is_active = TemplateURLData::ActiveStatus::kFalse;
@@ -2317,6 +2318,7 @@
     if (turl->is_active() == TemplateURLData::ActiveStatus::kUnspecified &&
         (!turl->safe_for_autoreplace() || turl->usage_count() > 0)) {
       turl->data_.is_active = TemplateURLData::ActiveStatus::kTrue;
+      turl->data_.safe_for_autoreplace = false;
       if (web_data_service_)
         web_data_service_->UpdateKeyword(turl->data());
     }
diff --git a/components/session_proto_db/DIR_METADATA b/components/session_proto_db/DIR_METADATA
new file mode 100644
index 0000000..676fe2a
--- /dev/null
+++ b/components/session_proto_db/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>Shopping"
+}
+team_email: "chrome-shopping@google.com"
diff --git a/components/test/data/autofill/heuristics/output/147_panera.custhelp.com_app_ask.out b/components/test/data/autofill/heuristics/output/147_panera.custhelp.com_app_ask.out
index 1261b49..a879f8e 100644
--- a/components/test/data/autofill/heuristics/output/147_panera.custhelp.com_app_ask.out
+++ b/components/test/data/autofill/heuristics/output/147_panera.custhelp.com_app_ask.out
@@ -27,10 +27,10 @@
 UNKNOWN_TYPE | Incident.CustomFields.c.gift_card_action | Gift Card Action |  | Incident.CustomFields.c.escalated_gift_card_devalue_1
 UNKNOWN_TYPE | Incident.CustomFields.c.gift_card_issuer_person | Gift Card Issuer (person) | 588 | Incident.CustomFields.c.escalated_gift_card_devalue_1
 UNKNOWN_TYPE | Incident.CustomFields.c.gift_card_appeasement_amt | Gift Card Appeasement $ Optional Optional |  | Incident.CustomFields.c.escalated_gift_card_devalue_1
-NUMERIC_QUANTITY | Incident.CustomFields.c.gift_card_amount_new | Gift Card Amount (new) Optional Optional |  | Incident.CustomFields.c.escalated_gift_card_devalue_1
+UNKNOWN_TYPE | Incident.CustomFields.c.gift_card_amount_new | Gift Card Amount (new) Optional Optional |  | Incident.CustomFields.c.escalated_gift_card_devalue_1
 UNKNOWN_TYPE | Incident.CustomFields.c.gift_card_new_card | Gift Card - New Card # Optional Optional |  | Incident.CustomFields.c.escalated_gift_card_devalue_1
 UNKNOWN_TYPE | Incident.CustomFields.c.gift_card_box_number | Gift Card Box # Optional Optional |  | Incident.CustomFields.c.escalated_gift_card_devalue_1
-NUMERIC_QUANTITY | Incident.CustomFields.c.gift_card_frozen_amount | Gift Card Amount (frozen) Optional Optional |  | Incident.CustomFields.c.escalated_gift_card_devalue_1
+UNKNOWN_TYPE | Incident.CustomFields.c.gift_card_frozen_amount | Gift Card Amount (frozen) Optional Optional |  | Incident.CustomFields.c.escalated_gift_card_devalue_1
 UNKNOWN_TYPE | Incident.CustomFields.c.gift_card_frozen_card_number | Gift Card Frozen Card # Optional Optional |  | Incident.CustomFields.c.escalated_gift_card_devalue_1
 UNKNOWN_TYPE | Incident.CustomFields.c.gift_card_issuing_location | Gift Card Issuing Location Optional Optional |  | Incident.CustomFields.c.escalated_gift_card_devalue_1
 UNKNOWN_TYPE | Incident.CustomFields.c.chat_type | Chat Topic Please select the Chat topic that best fits the issue |  | Incident.CustomFields.c.escalated_gift_card_devalue_1
diff --git a/components/variations/study_filtering.cc b/components/variations/study_filtering.cc
index 77613591..6710670 100644
--- a/components/variations/study_filtering.cc
+++ b/components/variations/study_filtering.cc
@@ -268,7 +268,8 @@
     }
 
     if (processed_study.ShouldStudyUseLowEntropy() &&
-        layers.IsLayerUsingDefaultEntropy(study.layer().layer_id())) {
+        layers.ActiveLayerMemberDependsOnHighEntropy(
+            study.layer().layer_id())) {
       DVLOG(1) << "Filtered out study " << study.name()
                << " due to requiring a low entropy source yet being a member "
                   "of a layer using the default entropy source.";
@@ -368,12 +369,14 @@
 
 }  // namespace internal
 
-void FilterAndValidateStudies(const VariationsSeed& seed,
-                              const ClientFilterableState& client_state,
-                              const VariationsLayers& layers,
-                              std::vector<ProcessedStudy>* filtered_studies) {
+std::vector<ProcessedStudy> FilterAndValidateStudies(
+    const VariationsSeed& seed,
+    const ClientFilterableState& client_state,
+    const VariationsLayers& layers) {
   DCHECK(client_state.version.IsValid());
 
+  std::vector<ProcessedStudy> filtered_studies;
+
   // Don't create two studies with the same name.
   std::set<std::string> created_studies;
 
@@ -387,10 +390,11 @@
       continue;
 
     if (!base::Contains(created_studies, processed_study.study()->name())) {
-      filtered_studies->push_back(processed_study);
+      filtered_studies.push_back(processed_study);
       created_studies.insert(processed_study.study()->name());
     }
   }
+  return filtered_studies;
 }
 
 }  // namespace variations
diff --git a/components/variations/study_filtering.h b/components/variations/study_filtering.h
index 38ac105..871dc15 100644
--- a/components/variations/study_filtering.h
+++ b/components/variations/study_filtering.h
@@ -108,15 +108,14 @@
 
 }  // namespace internal
 
-// Filters the list of studies in |seed| according ot the |client_state|, and
-// validates and pre-processes them, adding any kept studies to the
-// |filtered_studies| list. Ensures that the resulting list will not have more
-// than one study with the same name.
+// Validates and preprocesses studies in |seed|, filters them according to
+// the |client_state| and |layers|, and ensures the result has at most one
+// study with the same name.
 COMPONENT_EXPORT(VARIATIONS)
-void FilterAndValidateStudies(const VariationsSeed& seed,
-                              const ClientFilterableState& client_state,
-                              const VariationsLayers& layers,
-                              std::vector<ProcessedStudy>* filtered_studies);
+std::vector<ProcessedStudy> FilterAndValidateStudies(
+    const VariationsSeed& seed,
+    const ClientFilterableState& client_state,
+    const VariationsLayers& layers);
 
 }  // namespace variations
 
diff --git a/components/variations/study_filtering_unittest.cc b/components/variations/study_filtering_unittest.cc
index 29699a3..ffe503dc 100644
--- a/components/variations/study_filtering_unittest.cc
+++ b/components/variations/study_filtering_unittest.cc
@@ -702,9 +702,8 @@
   client_state.form_factor = Study::DESKTOP;
   client_state.platform = Study::PLATFORM_ANDROID;
 
-  std::vector<ProcessedStudy> processed_studies;
-  FilterAndValidateStudies(seed, client_state, VariationsLayers(),
-                           &processed_studies);
+  std::vector<ProcessedStudy> processed_studies =
+      FilterAndValidateStudies(seed, client_state, VariationsLayers());
 
   // Check that only the first kTrial1Name study was kept.
   ASSERT_EQ(2U, processed_studies.size());
@@ -773,9 +772,8 @@
   client_state.os_version = base::Version("1.2.3");
 
   base::HistogramTester histogram_tester;
-  std::vector<ProcessedStudy> processed_studies;
-  FilterAndValidateStudies(seed, client_state, VariationsLayers(),
-                           &processed_studies);
+  std::vector<ProcessedStudy> processed_studies =
+      FilterAndValidateStudies(seed, client_state, VariationsLayers());
 
   ASSERT_EQ(0U, processed_studies.size());
   histogram_tester.ExpectTotalCount("Variations.InvalidStudyReason",
@@ -809,9 +807,8 @@
   client_state.platform = Study::PLATFORM_ANDROID;
 
   base::HistogramTester histogram_tester;
-  std::vector<ProcessedStudy> processed_studies;
-  FilterAndValidateStudies(seed, client_state, VariationsLayers(),
-                           &processed_studies);
+  std::vector<ProcessedStudy> processed_studies =
+      FilterAndValidateStudies(seed, client_state, VariationsLayers());
 
   ASSERT_EQ(0U, processed_studies.size());
   histogram_tester.ExpectUniqueSample("Variations.InvalidStudyReason", 8, 1);
@@ -868,9 +865,8 @@
     client_state.session_consistency_country = kSessionCountry;
     client_state.permanent_consistency_country = kPermanentCountry;
 
-    std::vector<ProcessedStudy> processed_studies;
-    FilterAndValidateStudies(seed, client_state, VariationsLayers(),
-                             &processed_studies);
+    std::vector<ProcessedStudy> processed_studies =
+        FilterAndValidateStudies(seed, client_state, VariationsLayers());
 
     EXPECT_EQ(test.expect_study_kept, !processed_studies.empty());
   }
diff --git a/components/variations/variations_layers.cc b/components/variations/variations_layers.cc
index 2b0833e..448d852 100644
--- a/components/variations/variations_layers.cc
+++ b/components/variations/variations_layers.cc
@@ -10,48 +10,25 @@
 
 namespace {
 
-// Returns a double in the [0, 1] range to be used to select a slot within
-// a layer with the given randomization seed value.
-double GetEntropyForLayer(
-    const base::FieldTrial::EntropyProvider& entropy_provider,
-    uint32_t randomization_seed) {
-  // GetEntropyForTrial will ignore the trial_name parameter in favor of the
-  // randomization_seed.
-  return entropy_provider.GetEntropyForTrial(/*trial_name=*/"",
-                                             randomization_seed);
-}
-
 // Iterates through the members of the given layer proto definition, and
-// returns the ID of the member which contains that slot (if any).
-absl::optional<uint32_t> FindActiveMemberBySlot(uint32_t chosen_slot,
-                                                const Layer& layer_proto) {
+// returns the member which contains that slot (if any).
+const Layer::LayerMember* FindActiveMemberBySlot(uint32_t chosen_slot,
+                                                 const Layer& layer_proto) {
   for (const Layer::LayerMember& member : layer_proto.members()) {
     if (!member.id())
       continue;
 
     for (const Layer::LayerMember::SlotRange& slot : member.slots()) {
       if (slot.start() <= chosen_slot && chosen_slot <= slot.end())
-        return member.id();
+        return &member;
     }
   }
 
-  return absl::nullopt;
+  return nullptr;
 }
 
 }  // namespace
 
-VariationsLayers::LayerInfo::LayerInfo(
-    absl::optional<uint32_t> active_member_id,
-    Layer::EntropyMode entropy_mode)
-    : active_member_id(active_member_id), entropy_mode(entropy_mode) {}
-
-VariationsLayers::LayerInfo::~LayerInfo() = default;
-
-VariationsLayers::LayerInfo::LayerInfo(const LayerInfo& other) {
-  active_member_id = other.active_member_id;
-  entropy_mode = other.entropy_mode;
-}
-
 VariationsLayers::VariationsLayers(const VariationsSeed& seed,
                                    const EntropyProviders& entropy_providers) {
   // TODO(crbug.com/1154033): Support a way to expire old/unused layers so they
@@ -71,27 +48,24 @@
     return;
   }
 
-  double entropy_value;
-  if (layer_proto.entropy_mode() == Layer::LOW) {
-    entropy_value =
-        GetEntropyForLayer(entropy_providers.low_entropy(), layer_proto.salt());
-  } else {
-    entropy_value = GetEntropyForLayer(entropy_providers.default_entropy(),
-                                       layer_proto.salt());
+  if (layer_proto.entropy_mode() != Layer::LOW &&
+      layer_proto.entropy_mode() != Layer::DEFAULT) {
+    return;
   }
 
-  const double kEpsilon = 1e-8;
-  // Add a tiny epsilon to get consistent values when converting the double
-  // to the integer slots; see comment in
-  // base::FieldTrialList::GetGroupBoundaryValue() for more details.
-  uint32_t chosen_slot = std::min(
-      static_cast<uint32_t>(layer_proto.num_slots() * entropy_value + kEpsilon),
-      layer_proto.num_slots() - 1);
+  const auto& entropy_provider = (layer_proto.entropy_mode() != Layer::LOW)
+                                     ? entropy_providers.default_entropy()
+                                     : entropy_providers.low_entropy();
 
+  uint32_t chosen_slot = entropy_provider.GetPseudorandomValue(
+      layer_proto.salt(), layer_proto.num_slots());
+
+  const auto* chosen_member = FindActiveMemberBySlot(chosen_slot, layer_proto);
+  if (!chosen_member)
+    return;
   active_member_for_layer_.emplace(
-      layer_proto.id(),
-      LayerInfo{FindActiveMemberBySlot(chosen_slot, layer_proto),
-                layer_proto.entropy_mode()});
+      layer_proto.id(), LayerInfo{.active_member_id = chosen_member->id(),
+                                  .entropy_mode = layer_proto.entropy_mode()});
 }
 
 bool VariationsLayers::IsLayerMemberActive(uint32_t layer_id,
@@ -101,10 +75,11 @@
     return false;
 
   return layer_iter->second.active_member_id &&
-         (member_id == layer_iter->second.active_member_id.value());
+         (member_id == layer_iter->second.active_member_id);
 }
 
-bool VariationsLayers::IsLayerUsingDefaultEntropy(uint32_t layer_id) const {
+bool VariationsLayers::ActiveLayerMemberDependsOnHighEntropy(
+    uint32_t layer_id) const {
   auto layer_iter = active_member_for_layer_.find(layer_id);
   if (layer_iter == active_member_for_layer_.end())
     return false;
diff --git a/components/variations/variations_layers.h b/components/variations/variations_layers.h
index 6f2007f..15901da2 100644
--- a/components/variations/variations_layers.h
+++ b/components/variations/variations_layers.h
@@ -15,8 +15,12 @@
 
 namespace variations {
 
-// Parses out the Variations Layers data from the provided seed and
-// chooses which member within each layer should be the active one.
+// A view over the layers defined within a variations seed.
+//
+// A layer defines a collection of mutually exclusive members. For each client,
+// at most one member will be assigned as its active member. Studies may be
+// conditioned on a particular member being active, in order to avoid overlap
+// with studies that require a different member to be active.
 class COMPONENT_EXPORT(VARIATIONS) VariationsLayers {
  public:
   VariationsLayers(const VariationsSeed& seed,
@@ -28,25 +32,23 @@
   VariationsLayers(const VariationsLayers&) = delete;
   VariationsLayers& operator=(const VariationsLayers&) = delete;
 
-  // Return whether the given layer has the given member active.
+  // Returns whether the given layer has the given member active.
   bool IsLayerMemberActive(uint32_t layer_id, uint32_t member_id) const;
 
-  // Return whether the layer should use the default entropy source
-  // (usually the high entropy source).
-  bool IsLayerUsingDefaultEntropy(uint32_t layer_id) const;
+  // Returns true if the layer has an active member and is configured to use
+  // DEFAULT entropy, which means that any study conditioned on it would leak
+  // information about the client's high entropy source (including whether or
+  // not the client _has_ a high entropy source).
+  bool ActiveLayerMemberDependsOnHighEntropy(uint32_t layer_id) const;
 
  private:
   void ConstructLayer(const EntropyProviders& entropy_providers,
                       const Layer& layer_proto);
 
   struct LayerInfo {
-    LayerInfo(absl::optional<uint32_t> active_member_id,
-              Layer::EntropyMode entropy_mode);
-    ~LayerInfo();
-    LayerInfo(const LayerInfo& other);  // = delete;
-    LayerInfo& operator=(const LayerInfo&) = delete;
-
-    absl::optional<uint32_t> active_member_id;
+    // Which layer member is active in the layer.
+    uint32_t active_member_id;
+    // The type of entropy the layer was configured to use.
     Layer::EntropyMode entropy_mode;
   };
   std::map<uint32_t, LayerInfo> active_member_for_layer_;
diff --git a/components/variations/variations_seed_processor.cc b/components/variations/variations_seed_processor.cc
index af8f4b6..31f9949b 100644
--- a/components/variations/variations_seed_processor.cc
+++ b/components/variations/variations_seed_processor.cc
@@ -246,9 +246,9 @@
     base::FeatureList* feature_list) {
   base::UmaHistogramCounts1000("Variations.AppliedSeed.StudyCount",
                                seed.study().size());
-  std::vector<ProcessedStudy> filtered_studies;
   VariationsLayers layers(seed, entropy_providers);
-  FilterAndValidateStudies(seed, client_state, layers, &filtered_studies);
+  std::vector<ProcessedStudy> filtered_studies =
+      FilterAndValidateStudies(seed, client_state, layers);
   SetSeedVersion(seed.version());
 
   for (const ProcessedStudy& study : filtered_studies) {
@@ -316,8 +316,7 @@
   // Check if any experiments need to be forced due to a command line
   // flag. Force the first experiment with an existing flag.
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  for (int i = 0; i < study.experiment_size(); ++i) {
-    const Study::Experiment& experiment = study.experiment(i);
+  for (const auto& experiment : study.experiment()) {
     if (ShouldForceExperiment(experiment, *command_line, *feature_list)) {
       base::FieldTrial* trial = base::FieldTrialList::CreateFieldTrial(
           study.name(), experiment.name());
@@ -358,8 +357,7 @@
 
   bool has_overrides = false;
   bool enables_or_disables_features = false;
-  for (int i = 0; i < study.experiment_size(); ++i) {
-    const Study::Experiment& experiment = study.experiment(i);
+  for (const auto& experiment : study.experiment()) {
     RegisterExperimentParams(study, experiment);
 
     // Groups with forcing flags have probability 0 and will never be selected.
diff --git a/components/variations/variations_seed_simulator.cc b/components/variations/variations_seed_simulator.cc
index 982c8fd..984f309 100644
--- a/components/variations/variations_seed_simulator.cc
+++ b/components/variations/variations_seed_simulator.cc
@@ -47,8 +47,7 @@
           study.name(), processed_study.total_probability(),
           processed_study.GetDefaultExperimentName(), entropy_value));
 
-  for (int i = 0; i < study.experiment_size(); ++i) {
-    const Study_Experiment& experiment = study.experiment(i);
+  for (const auto& experiment : study.experiment()) {
     // TODO(asvitkine): This needs to properly handle the case where a group was
     // forced via forcing_flag in the current state, so that it is not treated
     // as changed.
@@ -64,9 +63,9 @@
 // or NULL if it does not exist.
 const Study_Experiment* FindExperiment(const Study& study,
                                        const std::string& experiment_name) {
-  for (int i = 0; i < study.experiment_size(); ++i) {
-    if (study.experiment(i).name() == experiment_name)
-      return &study.experiment(i);
+  for (const auto& experiment : study.experiment()) {
+    if (experiment.name() == experiment_name)
+      return &experiment;
   }
   return nullptr;
 }
@@ -82,10 +81,10 @@
   if (static_cast<int>(params.size()) != experiment.param_size())
     return false;
 
-  for (int i = 0; i < experiment.param_size(); ++i) {
+  for (const auto& param : experiment.param()) {
     std::map<std::string, std::string>::const_iterator it =
-        params.find(experiment.param(i).name());
-    if (it == params.end() || it->second != experiment.param(i).value())
+        params.find(param.name());
+    if (it == params.end() || it->second != param.value())
       return false;
   }
 
@@ -113,9 +112,9 @@
 VariationsSeedSimulator::Result VariationsSeedSimulator::SimulateSeedStudies(
     const VariationsSeed& seed,
     const ClientFilterableState& client_state) {
-  std::vector<ProcessedStudy> filtered_studies;
   VariationsLayers layers(seed, entropy_providers_);
-  FilterAndValidateStudies(seed, client_state, layers, &filtered_studies);
+  std::vector<ProcessedStudy> filtered_studies =
+      FilterAndValidateStudies(seed, client_state, layers);
 
   return ComputeDifferences(filtered_studies, layers);
 }
@@ -127,8 +126,8 @@
   GetCurrentTrialState(&current_state);
 
   Result result;
-  for (size_t i = 0; i < processed_studies.size(); ++i) {
-    const Study& study = *processed_studies[i].study();
+  for (const auto& processed_study : processed_studies) {
+    const Study& study = *processed_study.study();
     std::map<std::string, std::string>::const_iterator it =
         current_state.find(study.name());
 
@@ -147,11 +146,10 @@
     const std::string& selected_group = it->second;
     ChangeType change_type = NO_CHANGE;
     if (study.consistency() == Study_Consistency_PERMANENT) {
-      change_type = PermanentStudyGroupChanged(processed_studies[i],
-                                               selected_group, layers);
+      change_type =
+          PermanentStudyGroupChanged(processed_study, selected_group, layers);
     } else if (study.consistency() == Study_Consistency_SESSION) {
-      change_type = SessionStudyGroupChanged(processed_studies[i],
-                                             selected_group);
+      change_type = SessionStudyGroupChanged(processed_study, selected_group);
     }
 
     switch (change_type) {
diff --git a/components/webapps/browser/installable/installable_manager.cc b/components/webapps/browser/installable/installable_manager.cc
index a38c3cbc..27b1d671 100644
--- a/components/webapps/browser/installable/installable_manager.cc
+++ b/components/webapps/browser/installable/installable_manager.cc
@@ -474,8 +474,8 @@
          (!params.valid_splash_icon || IsIconFetchComplete(IconUsage::kSplash));
 }
 
-void InstallableManager::Reset(absl::optional<InstallableStatusCode> error) {
-  DCHECK(!error || error.value() != NO_ERROR_DETECTED);
+void InstallableManager::Reset(InstallableStatusCode error) {
+  DCHECK(error != NO_ERROR_DETECTED);
   // Prevent any outstanding callbacks to or from this object from being called.
   weak_factory_.InvalidateWeakPtrs();
   icons_.clear();
@@ -484,11 +484,9 @@
   screenshots_downloading_ = 0;
   is_screenshots_fetch_complete_ = false;
 
-  // If we have paused tasks, we are waiting for a service worker.
-  if (error)
-    task_queue_.ResetWithError(error.value());
-  else
-    task_queue_.Reset();
+  // If we have paused tasks, we are waiting for a service worker. Execute the
+  // callbacks with the status_code being passed for the paused tasks.
+  task_queue_.ResetWithError(error);
 
   eligibility_ = std::make_unique<EligiblityProperty>();
   manifest_ = std::make_unique<ManifestProperty>();
@@ -1042,7 +1040,9 @@
 }
 
 void InstallableManager::WebContentsDestroyed() {
-  Reset();
+  // This ensures that we do not just hang callbacks on web_contents being
+  // destroyed.
+  Reset(RENDERER_EXITING);
   Observe(nullptr);
 }
 
diff --git a/components/webapps/browser/installable/installable_manager.h b/components/webapps/browser/installable/installable_manager.h
index ef51b63..8b9883b4 100644
--- a/components/webapps/browser/installable/installable_manager.h
+++ b/components/webapps/browser/installable/installable_manager.h
@@ -23,7 +23,6 @@
 #include "content/public/browser/service_worker_context_observer.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/mojom/manifest/manifest.mojom.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "url/gurl.h"
@@ -200,11 +199,11 @@
   // Returns true if |params| requires no more work to be done.
   bool IsComplete(const InstallableParams& params) const;
 
-  // Resets members to empty and removes all queued tasks.
+  // Resets members to empty and reports the given |error| to all queued tasks
+  // to run queued callbacks before removing the tasks.
   // Called when navigating to a new page or if the WebContents is destroyed
   // whilst waiting for a callback.
-  // If populated, the given |error| is reported to all queued tasks.
-  void Reset(absl::optional<InstallableStatusCode> error = absl::nullopt);
+  void Reset(InstallableStatusCode error);
 
   // Sets the fetched bit on the installable and icon subtasks.
   // Called if no manifest (or an empty manifest) was fetched from the site.
diff --git a/components/webapps/browser/installable/installable_task_queue.cc b/components/webapps/browser/installable/installable_task_queue.cc
index 55f8a97..cb70337 100644
--- a/components/webapps/browser/installable/installable_task_queue.cc
+++ b/components/webapps/browser/installable/installable_task_queue.cc
@@ -63,11 +63,6 @@
   tasks_.pop_front();
 }
 
-void InstallableTaskQueue::Reset() {
-  tasks_.clear();
-  paused_tasks_.clear();
-}
-
 void InstallableTaskQueue::ResetWithError(InstallableStatusCode code) {
   std::deque<InstallableTask> tasks = std::move(tasks_);
   std::deque<InstallableTask> paused_tasks = std::move(paused_tasks_);
diff --git a/components/webapps/browser/installable/installable_task_queue.h b/components/webapps/browser/installable/installable_task_queue.h
index c062a29..0ee07d1 100644
--- a/components/webapps/browser/installable/installable_task_queue.h
+++ b/components/webapps/browser/installable/installable_task_queue.h
@@ -58,9 +58,6 @@
   // Advances to the next task.
   void Next();
 
-  // Clears all tasks from the main and paused list.
-  void Reset();
-
   // Clears all tasks from the main and paused list, and then calls the callback
   // on all of them with the given status code.
   void ResetWithError(InstallableStatusCode code);
diff --git a/components/webapps/browser/installable/installable_task_queue_unittest.cc b/components/webapps/browser/installable/installable_task_queue_unittest.cc
index 6e23ea12..4d3a6bf 100644
--- a/components/webapps/browser/installable/installable_task_queue_unittest.cc
+++ b/components/webapps/browser/installable/installable_task_queue_unittest.cc
@@ -58,7 +58,7 @@
   EXPECT_TRUE(task_queue.HasPaused());
   EXPECT_TRUE(IsEqual(task2, task_queue.Current()));
 
-  task_queue.Reset();
+  task_queue.ResetWithError(InstallableStatusCode::NO_ERROR_DETECTED);
   EXPECT_FALSE(task_queue.HasCurrent());
   EXPECT_FALSE(task_queue.HasPaused());
 }
@@ -86,7 +86,7 @@
   EXPECT_TRUE(task_queue.HasCurrent());
   EXPECT_TRUE(IsEqual(task1, task_queue.Current()));
 
-  task_queue.Reset();
+  task_queue.ResetWithError(InstallableStatusCode::NO_ERROR_DETECTED);
   EXPECT_FALSE(task_queue.HasCurrent());
   EXPECT_FALSE(task_queue.HasPaused());
 }
diff --git a/content/browser/file_system_access/file_system_access_manager_impl.cc b/content/browser/file_system_access/file_system_access_manager_impl.cc
index 06b7788..e727578 100644
--- a/content/browser/file_system_access/file_system_access_manager_impl.cc
+++ b/content/browser/file_system_access/file_system_access_manager_impl.cc
@@ -675,6 +675,55 @@
     HandleType file_type) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
+  if (!permission_context_) {
+    DidVerifySensitiveDirectoryAccessForDataTransfer(
+        binding_context, file_path, url, file_type,
+        std::move(token_resolved_callback), SensitiveEntryResult::kAllowed);
+    return;
+  }
+
+  // Drag-and-dropped files cannot be from a sandboxed file system.
+  DCHECK(url.type() == storage::FileSystemType::kFileSystemTypeLocal ||
+         url.type() == storage::FileSystemType::kFileSystemTypeExternal);
+  PathType path_type =
+      url.type() == storage::FileSystemType::kFileSystemTypeLocal
+          ? PathType::kLocal
+          : PathType::kExternal;
+  // TODO(https://crbug.com/1370433): Update ConfirmSensitiveEntryAccess() to
+  // take a UserAction and show a prompt specific to D&D accordingly. For now,
+  // run the same security checks and show the same prompt for D&D as for the
+  // file picker.
+  ui::SelectFileDialog::Type dialog_type =
+      file_type == HandleType::kFile
+          ? ui::SelectFileDialog::Type::SELECT_OPEN_FILE
+          : ui::SelectFileDialog::Type::SELECT_UPLOAD_FOLDER;
+  permission_context_->ConfirmSensitiveEntryAccess(
+      binding_context.storage_key.origin(), path_type, file_path, file_type,
+      dialog_type, binding_context.frame_id,
+      base::BindOnce(&FileSystemAccessManagerImpl::
+                         DidVerifySensitiveDirectoryAccessForDataTransfer,
+                     weak_factory_.GetWeakPtr(), binding_context, file_path,
+                     url, file_type, std::move(token_resolved_callback)));
+}
+
+void FileSystemAccessManagerImpl::
+    DidVerifySensitiveDirectoryAccessForDataTransfer(
+        const BindingContext& binding_context,
+        const base::FilePath& file_path,
+        const storage::FileSystemURL& url,
+        HandleType file_type,
+        GetEntryFromDataTransferTokenCallback token_resolved_callback,
+        SensitiveEntryResult result) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (result != SensitiveEntryResult::kAllowed) {
+    std::move(token_resolved_callback)
+        .Run(file_system_access_error::FromStatus(
+                 blink::mojom::FileSystemAccessStatus::kOperationAborted),
+             blink::mojom::FileSystemAccessEntryPtr());
+    return;
+  }
+
   SharedHandleState shared_handle_state =
       GetSharedHandleStateForPath(file_path, binding_context.storage_key,
                                   file_type, UserAction::kDragAndDrop);
@@ -692,7 +741,8 @@
         file_path.BaseName().AsUTF8Unsafe());
   }
 
-  std::move(token_resolved_callback).Run(std::move(entry));
+  std::move(token_resolved_callback)
+      .Run(file_system_access_error::Ok(), std::move(entry));
 }
 
 void FileSystemAccessManagerImpl::GetFileHandleFromToken(
diff --git a/content/browser/file_system_access/file_system_access_manager_impl.h b/content/browser/file_system_access/file_system_access_manager_impl.h
index 2805a9c..47cd5e2 100644
--- a/content/browser/file_system_access/file_system_access_manager_impl.h
+++ b/content/browser/file_system_access/file_system_access_manager_impl.h
@@ -513,6 +513,18 @@
       GetEntryFromDataTransferTokenCallback token_resolved_callback,
       FileSystemAccessPermissionContext::HandleType file_type);
 
+  // Calls `token_resolved_callback` with a FileSystemAccessEntry representing
+  // the file/directory at `file_path`. Called by
+  // ResolveDataTransferTokenWithFileType after it verifies the token does not
+  // refer to a sensitive path.
+  void DidVerifySensitiveDirectoryAccessForDataTransfer(
+      const BindingContext& binding_context,
+      const base::FilePath& file_path,
+      const storage::FileSystemURL& url,
+      FileSystemAccessPermissionContext::HandleType file_type,
+      GetEntryFromDataTransferTokenCallback token_resolved_callback,
+      FileSystemAccessPermissionContext::SensitiveEntryResult result);
+
   // `root_permission_path` is path that the user selected in a file or
   // directory picker which led to the site having access to this URL. All
   // permissions related to the URL are based on this path.
diff --git a/content/browser/file_system_access/file_system_access_manager_impl_unittest.cc b/content/browser/file_system_access/file_system_access_manager_impl_unittest.cc
index 1e26d7b..bafc0c2 100644
--- a/content/browser/file_system_access/file_system_access_manager_impl_unittest.cc
+++ b/content/browser/file_system_access/file_system_access_manager_impl_unittest.cc
@@ -247,6 +247,16 @@
         path_type, file_path, kBindingContext.process_id(),
         token_remote.InitWithNewPipeAndPassReceiver());
 
+    EXPECT_CALL(
+        permission_context_,
+        ConfirmSensitiveEntryAccess_(
+            kTestStorageKey.origin(),
+            FileSystemAccessPermissionContext::PathType::kLocal, file_path,
+            FileSystemAccessPermissionContext::HandleType::kFile,
+            ui::SelectFileDialog::Type::SELECT_OPEN_FILE, kFrameId, testing::_))
+        .WillOnce(RunOnceCallback<6>(
+            FileSystemAccessPermissionContext::SensitiveEntryResult::kAllowed));
+
     // Expect permission requests when the token is sent to be redeemed.
     EXPECT_CALL(
         permission_context_,
@@ -264,10 +274,14 @@
 
     // Attempt to resolve `token_remote` and store the resulting
     // FileSystemAccessFileHandle in `file_remote`.
-    base::test::TestFuture<blink::mojom::FileSystemAccessEntryPtr> future;
+    base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
+                           blink::mojom::FileSystemAccessEntryPtr>
+        future;
     manager_remote_->GetEntryFromDataTransferToken(std::move(token_remote),
                                                    future.GetCallback());
-    auto file_system_access_entry = future.Take();
+    DCHECK_EQ(future.Get<0>()->status,
+              blink::mojom::FileSystemAccessStatus::kOk);
+    auto file_system_access_entry = std::get<1>(future.Take());
 
     ASSERT_FALSE(file_system_access_entry.is_null());
     ASSERT_TRUE(file_system_access_entry->entry_handle->is_file());
@@ -290,6 +304,17 @@
         path_type, dir_path, kBindingContext.process_id(),
         token_remote.InitWithNewPipeAndPassReceiver());
 
+    EXPECT_CALL(
+        permission_context_,
+        ConfirmSensitiveEntryAccess_(
+            kTestStorageKey.origin(),
+            FileSystemAccessPermissionContext::PathType::kLocal, dir_path,
+            FileSystemAccessPermissionContext::HandleType::kDirectory,
+            ui::SelectFileDialog::Type::SELECT_UPLOAD_FOLDER, kFrameId,
+            testing::_))
+        .WillOnce(RunOnceCallback<6>(
+            FileSystemAccessPermissionContext::SensitiveEntryResult::kAllowed));
+
     // Expect permission requests when the token is sent to be redeemed.
     EXPECT_CALL(
         permission_context_,
@@ -307,11 +332,14 @@
 
     // Attempt to resolve `token_remote` and store the resulting
     // FileSystemAccessDirectoryHandle in `dir_remote`.
-    base::test::TestFuture<blink::mojom::FileSystemAccessEntryPtr>
+    base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
+                           blink::mojom::FileSystemAccessEntryPtr>
         get_entry_future;
     manager_remote_->GetEntryFromDataTransferToken(
         std::move(token_remote), get_entry_future.GetCallback());
-    auto file_system_access_entry = get_entry_future.Take();
+    DCHECK_EQ(get_entry_future.Get<0>()->status,
+              blink::mojom::FileSystemAccessStatus::kOk);
+    auto file_system_access_entry = std::get<1>(get_entry_future.Take());
 
     ASSERT_FALSE(file_system_access_entry.is_null());
     ASSERT_TRUE(file_system_access_entry->entry_handle->is_directory());
@@ -1254,6 +1282,74 @@
   EXPECT_EQ("Invalid renderer ID.", bad_message_observer.WaitForBadMessage());
 }
 
+TEST_F(FileSystemAccessManagerImplTest,
+       GetEntryFromDataTransferToken_File_SensitivePath) {
+  base::FilePath file_path = dir_.GetPath().AppendASCII("mr_file");
+  ASSERT_TRUE(base::CreateTemporaryFile(&file_path));
+
+  mojo::PendingRemote<blink::mojom::FileSystemAccessDataTransferToken>
+      token_remote;
+  manager_->CreateFileSystemAccessDataTransferToken(
+      FileSystemAccessEntryFactory::PathType::kLocal, file_path,
+      kBindingContext.process_id(),
+      token_remote.InitWithNewPipeAndPassReceiver());
+
+  EXPECT_CALL(
+      permission_context_,
+      ConfirmSensitiveEntryAccess_(
+          kTestStorageKey.origin(),
+          FileSystemAccessPermissionContext::PathType::kLocal, file_path,
+          FileSystemAccessPermissionContext::HandleType::kFile,
+          ui::SelectFileDialog::Type::SELECT_OPEN_FILE, kFrameId, testing::_))
+      .WillOnce(RunOnceCallback<6>(
+          FileSystemAccessPermissionContext::SensitiveEntryResult::kAbort));
+
+  // Attempt to resolve `token_remote` should abort.
+  base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
+                         blink::mojom::FileSystemAccessEntryPtr>
+      get_entry_future;
+  manager_remote_->GetEntryFromDataTransferToken(
+      std::move(token_remote), get_entry_future.GetCallback());
+  DCHECK_EQ(get_entry_future.Get<0>()->status,
+            blink::mojom::FileSystemAccessStatus::kOperationAborted);
+  auto file_system_access_entry = std::get<1>(get_entry_future.Take());
+  EXPECT_TRUE(file_system_access_entry.is_null());
+}
+
+TEST_F(FileSystemAccessManagerImplTest,
+       GetEntryFromDataTransferToken_Directory_SensitivePath) {
+  const base::FilePath& kDirPath = dir_.GetPath().AppendASCII("mr_directory");
+  ASSERT_TRUE(base::CreateDirectory(kDirPath));
+
+  mojo::PendingRemote<blink::mojom::FileSystemAccessDataTransferToken>
+      token_remote;
+  manager_->CreateFileSystemAccessDataTransferToken(
+      FileSystemAccessEntryFactory::PathType::kLocal, kDirPath,
+      kBindingContext.process_id(),
+      token_remote.InitWithNewPipeAndPassReceiver());
+
+  EXPECT_CALL(permission_context_,
+              ConfirmSensitiveEntryAccess_(
+                  kTestStorageKey.origin(),
+                  FileSystemAccessPermissionContext::PathType::kLocal, kDirPath,
+                  FileSystemAccessPermissionContext::HandleType::kDirectory,
+                  ui::SelectFileDialog::Type::SELECT_UPLOAD_FOLDER, kFrameId,
+                  testing::_))
+      .WillOnce(RunOnceCallback<6>(
+          FileSystemAccessPermissionContext::SensitiveEntryResult::kAbort));
+
+  // Attempt to resolve `token_remote` should abort.
+  base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
+                         blink::mojom::FileSystemAccessEntryPtr>
+      get_entry_future;
+  manager_remote_->GetEntryFromDataTransferToken(
+      std::move(token_remote), get_entry_future.GetCallback());
+  DCHECK_EQ(get_entry_future.Get<0>()->status,
+            blink::mojom::FileSystemAccessStatus::kOperationAborted);
+  auto file_system_access_entry = std::get<1>(get_entry_future.Take());
+  EXPECT_TRUE(file_system_access_entry.is_null());
+}
+
 // FileSystemAccessManager should refuse to resolve a
 // FileSystemAccessDataTransferToken if the value of the token was not
 // recognized by the FileSystemAccessManager.
diff --git a/content/browser/loader/navigation_early_hints_browsertest.cc b/content/browser/loader/navigation_early_hints_browsertest.cc
index 79a4929..10b7e51 100644
--- a/content/browser/loader/navigation_early_hints_browsertest.cc
+++ b/content/browser/loader/navigation_early_hints_browsertest.cc
@@ -151,7 +151,8 @@
     feature_list_.InitWithFeatures(
         {features::kEarlyHintsPreloadForNavigation,
          net::features::kSplitCacheByNetworkIsolationKey},
-        {net::features::kForceIsolationInfoFrameOriginToTopLevelFrame});
+        {net::features::kForceIsolationInfoFrameOriginToTopLevelFrame,
+         net::features::kEnableDoubleKeyNetworkAnonymizationKey});
   }
   ~NavigationEarlyHintsTest() override = default;
 
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc
index 172e3957..c2ccf90 100644
--- a/content/browser/navigation_browsertest.cc
+++ b/content/browser/navigation_browsertest.cc
@@ -4506,7 +4506,8 @@
   NetworkIsolationSplitCacheAppendIframeOrigin() {
     feature_list_.InitWithFeatures(
         {net::features::kSplitCacheByNetworkIsolationKey},
-        {net::features::kForceIsolationInfoFrameOriginToTopLevelFrame});
+        {net::features::kForceIsolationInfoFrameOriginToTopLevelFrame,
+         net::features::kEnableDoubleKeyNetworkAnonymizationKey});
   }
 
  private:
diff --git a/content/browser/network/split_cache_browsertest.cc b/content/browser/network/split_cache_browsertest.cc
index b8826655..10dfc34 100644
--- a/content/browser/network/split_cache_browsertest.cc
+++ b/content/browser/network/split_cache_browsertest.cc
@@ -393,7 +393,8 @@
   SplitCacheRegistrableDomainContentBrowserTest() {
     feature_list_.InitWithFeatures(
         {net::features::kSplitCacheByNetworkIsolationKey},
-        {net::features::kForceIsolationInfoFrameOriginToTopLevelFrame});
+        {net::features::kForceIsolationInfoFrameOriginToTopLevelFrame,
+         net::features::kEnableDoubleKeyNetworkAnonymizationKey});
   }
 
  private:
@@ -411,7 +412,8 @@
     std::vector<base::test::FeatureRef> disabled_features;
     disabled_features.push_back(
         net::features::kForceIsolationInfoFrameOriginToTopLevelFrame);
-
+    disabled_features.push_back(
+        net::features::kEnableDoubleKeyNetworkAnonymizationKey);
     // When the test parameter is true, we test the split cache with
     // PlzDedicatedWorker enabled.
     if (GetParam())
diff --git a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
index be17720..174db29 100644
--- a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
@@ -17587,7 +17587,7 @@
 }
 
 // Tests that if an entry is marked as skippable, it will not be reset if there
-// is a navigation to this entry again (crbug.com/112129) using history.back/
+// is a navigation to this entry again (crbug.com/1121293) using history.back/
 // forward.
 IN_PROC_BROWSER_TEST_P(NavigationControllerHistoryInterventionBrowserTest,
                        DoNotResetSkipOnHistoryBackAPI) {
diff --git a/content/browser/web_package/web_bundle_element_browsertest.cc b/content/browser/web_package/web_bundle_element_browsertest.cc
index 9e0ccfb90..415099a 100644
--- a/content/browser/web_package/web_bundle_element_browsertest.cc
+++ b/content/browser/web_package/web_bundle_element_browsertest.cc
@@ -132,7 +132,8 @@
  protected:
   WebBundleElementBrowserTest() {
     feature_list_.InitWithFeatures(
-        {}, {net::features::kForceIsolationInfoFrameOriginToTopLevelFrame});
+        {}, {net::features::kForceIsolationInfoFrameOriginToTopLevelFrame,
+             net::features::kEnableDoubleKeyNetworkAnonymizationKey});
   }
   ~WebBundleElementBrowserTest() override = default;
 
diff --git a/content/browser/webrtc/webrtc_image_capture_browsertest.cc b/content/browser/webrtc/webrtc_image_capture_browsertest.cc
index 34e171f..a117aed 100644
--- a/content/browser/webrtc/webrtc_image_capture_browsertest.cc
+++ b/content/browser/webrtc/webrtc_image_capture_browsertest.cc
@@ -17,10 +17,6 @@
 #include "media/capture/video/fake_video_capture_device_factory.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 
-#if BUILDFLAG(IS_ANDROID)
-#include "base/android/build_info.h"
-#endif
-
 namespace content {
 
 // Disable FocusDistance test which fails with Logitech cameras.
@@ -116,14 +112,6 @@
   // Tries to run a |command| JS test, returning true if the test can be safely
   // skipped or it works as intended, or false otherwise.
   virtual bool RunImageCaptureTestCase(const std::string& command) {
-#if BUILDFLAG(IS_ANDROID)
-    // TODO(mcasas): fails on Lollipop devices: https://crbug.com/634811
-    if (base::android::BuildInfo::GetInstance()->sdk_int() <
-        base::android::SDK_VERSION_MARSHMALLOW) {
-      return true;
-    }
-#endif
-
     GURL url(embedded_test_server()->GetURL(kImageCaptureHtmlFile));
     EXPECT_TRUE(NavigateToURL(shell(), url));
 
diff --git a/content/renderer/media/renderer_webaudiodevice_impl.cc b/content/renderer/media/renderer_webaudiodevice_impl.cc
index 0e8bf85..149f423 100644
--- a/content/renderer/media/renderer_webaudiodevice_impl.cc
+++ b/content/renderer/media/renderer_webaudiodevice_impl.cc
@@ -29,6 +29,7 @@
 using blink::AudioDeviceFactory;
 using blink::WebAudioDevice;
 using blink::WebAudioLatencyHint;
+using blink::WebAudioSinkDescriptor;
 using blink::WebLocalFrame;
 using blink::WebVector;
 using blink::WebView;
@@ -110,6 +111,7 @@
 }  // namespace
 
 std::unique_ptr<RendererWebAudioDeviceImpl> RendererWebAudioDeviceImpl::Create(
+    const WebAudioSinkDescriptor& sink_descriptor,
     media::ChannelLayout layout,
     int number_of_output_channels,
     const blink::WebAudioLatencyHint& latency_hint,
@@ -117,12 +119,13 @@
     const base::UnguessableToken& session_id) {
   return std::unique_ptr<RendererWebAudioDeviceImpl>(
       new RendererWebAudioDeviceImpl(
-          layout, number_of_output_channels, latency_hint, callback, session_id,
-          base::BindOnce(&GetOutputDeviceParameters),
+          sink_descriptor, layout, number_of_output_channels, latency_hint,
+          callback, session_id, base::BindOnce(&GetOutputDeviceParameters),
           base::BindOnce(&FrameTokenFromCurrentContext)));
 }
 
 RendererWebAudioDeviceImpl::RendererWebAudioDeviceImpl(
+    const WebAudioSinkDescriptor& sink_descriptor,
     media::ChannelLayout layout,
     int number_of_output_channels,
     const blink::WebAudioLatencyHint& latency_hint,
@@ -130,7 +133,8 @@
     const base::UnguessableToken& session_id,
     OutputDeviceParamsCallback device_params_cb,
     RenderFrameTokenCallback render_frame_token_cb)
-    : latency_hint_(latency_hint),
+    : sink_descriptor_(sink_descriptor),
+      latency_hint_(latency_hint),
       client_callback_(callback),
       session_id_(session_id),
       frame_token_(std::move(render_frame_token_cb).Run()) {
@@ -139,7 +143,7 @@
 
   media::AudioParameters hardware_params(
       std::move(device_params_cb)
-          .Run(frame_token_, session_id_, std::string()));
+          .Run(frame_token_, session_id_, sink_descriptor_.SinkId().Ascii()));
 
   // On systems without audio hardware the returned parameters may be invalid.
   // In which case just choose whatever we want for the fake device.
@@ -186,7 +190,8 @@
 
   sink_ = AudioDeviceFactory::GetInstance()->NewAudioRendererSink(
       GetLatencyHintSourceType(latency_hint_.Category()), frame_token_,
-      media::AudioSinkParameters(session_id_, std::string()));
+      media::AudioSinkParameters(session_id_,
+                                 sink_descriptor_.SinkId().Ascii()));
 
   // Use a task runner instead of the render thread for fake Render() calls
   // since it has special connotations for Blink and garbage collection. Timeout
diff --git a/content/renderer/media/renderer_webaudiodevice_impl.h b/content/renderer/media/renderer_webaudiodevice_impl.h
index 31dd077..0684ccf 100644
--- a/content/renderer/media/renderer_webaudiodevice_impl.h
+++ b/content/renderer/media/renderer_webaudiodevice_impl.h
@@ -18,6 +18,7 @@
 #include "third_party/blink/public/common/tokens/tokens.h"
 #include "third_party/blink/public/platform/web_audio_device.h"
 #include "third_party/blink/public/platform/web_audio_latency_hint.h"
+#include "third_party/blink/public/platform/web_audio_sink_descriptor.h"
 #include "third_party/blink/public/platform/web_vector.h"
 
 namespace base {
@@ -43,6 +44,7 @@
   ~RendererWebAudioDeviceImpl() override;
 
   static std::unique_ptr<RendererWebAudioDeviceImpl> Create(
+      const blink::WebAudioSinkDescriptor& sink_descriptor,
       media::ChannelLayout layout,
       int number_of_output_channels,
       const blink::WebAudioLatencyHint& latency_hint,
@@ -86,13 +88,15 @@
   // Callback get render frame token for current context (for tests).
   using RenderFrameTokenCallback = base::OnceCallback<blink::LocalFrameToken()>;
 
-  RendererWebAudioDeviceImpl(media::ChannelLayout layout,
-                             int number_of_output_channels,
-                             const blink::WebAudioLatencyHint& latency_hint,
-                             blink::WebAudioDevice::RenderCallback* callback,
-                             const base::UnguessableToken& session_id,
-                             OutputDeviceParamsCallback device_params_cb,
-                             RenderFrameTokenCallback render_frame_token_cb);
+  RendererWebAudioDeviceImpl(
+      const blink::WebAudioSinkDescriptor& sink_descriptor,
+      media::ChannelLayout layout,
+      int number_of_output_channels,
+      const blink::WebAudioLatencyHint& latency_hint,
+      blink::WebAudioDevice::RenderCallback* callback,
+      const base::UnguessableToken& session_id,
+      OutputDeviceParamsCallback device_params_cb,
+      RenderFrameTokenCallback render_frame_token_cb);
 
  private:
   scoped_refptr<base::SingleThreadTaskRunner> GetSilentSinkTaskRunner();
@@ -101,6 +105,9 @@
 
   media::AudioParameters sink_params_;
 
+  // To cache the device identifier for sink creation.
+  const blink::WebAudioSinkDescriptor sink_descriptor_;
+
   const blink::WebAudioLatencyHint latency_hint_;
 
   // Weak reference to the callback into WebKit code.
diff --git a/content/renderer/media/renderer_webaudiodevice_impl_unittest.cc b/content/renderer/media/renderer_webaudiodevice_impl_unittest.cc
index 862902e..081cb2cb 100644
--- a/content/renderer/media/renderer_webaudiodevice_impl_unittest.cc
+++ b/content/renderer/media/renderer_webaudiodevice_impl_unittest.cc
@@ -46,14 +46,16 @@
 class RendererWebAudioDeviceImplUnderTest : public RendererWebAudioDeviceImpl {
  public:
   RendererWebAudioDeviceImplUnderTest(
+      const blink::WebAudioSinkDescriptor& sink_descriptor,
       media::ChannelLayout layout,
-      int channels,
+      int number_of_output_channels,
       const blink::WebAudioLatencyHint& latency_hint,
       blink::WebAudioDevice::RenderCallback* callback,
       const base::UnguessableToken& session_id)
       : RendererWebAudioDeviceImpl(
+            sink_descriptor,
             layout,
-            channels,
+            number_of_output_channels,
             latency_hint,
             callback,
             session_id,
@@ -71,16 +73,20 @@
   RendererWebAudioDeviceImplTest() {}
 
   void SetupDevice(blink::WebAudioLatencyHint latencyHint) {
+    blink::WebAudioSinkDescriptor
+        sink_descriptor(blink::WebString::FromASCII(std::string()));
     webaudio_device_ = std::make_unique<RendererWebAudioDeviceImplUnderTest>(
-        media::CHANNEL_LAYOUT_MONO, 1, latencyHint, this,
+        sink_descriptor, media::CHANNEL_LAYOUT_MONO, 1, latencyHint, this,
         base::UnguessableToken());
     webaudio_device_->SetSilentSinkTaskRunnerForTesting(
         blink::scheduler::GetSingleThreadTaskRunnerForTesting());
   }
 
   void SetupDevice(media::ChannelLayout layout, int channels) {
+    blink::WebAudioSinkDescriptor
+        sink_descriptor(blink::WebString::FromASCII(std::string()));
     webaudio_device_ = std::make_unique<RendererWebAudioDeviceImplUnderTest>(
-        layout, channels,
+        sink_descriptor, layout, channels,
         blink::WebAudioLatencyHint(
             blink::WebAudioLatencyHint::kCategoryInteractive),
         this, base::UnguessableToken());
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 9a29b478..4cedfbfa 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -91,6 +91,7 @@
 #include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
 #include "third_party/blink/public/platform/url_conversion.h"
 #include "third_party/blink/public/platform/web_audio_latency_hint.h"
+#include "third_party/blink/public/platform/web_audio_sink_descriptor.h"
 #include "third_party/blink/public/platform/web_code_cache_loader.h"
 #include "third_party/blink/public/platform/web_security_origin.h"
 #include "third_party/blink/public/platform/web_theme_engine.h"
@@ -124,6 +125,7 @@
 using blink::Platform;
 using blink::WebAudioDevice;
 using blink::WebAudioLatencyHint;
+using blink::WebAudioSinkDescriptor;
 using blink::WebMediaStreamTrack;
 using blink::WebString;
 using blink::WebURL;
@@ -470,19 +472,26 @@
 }
 
 std::unique_ptr<WebAudioDevice> RendererBlinkPlatformImpl::CreateAudioDevice(
-    unsigned output_channels,
+    const WebAudioSinkDescriptor& sink_descriptor,
+    unsigned number_of_output_channels,
     const blink::WebAudioLatencyHint& latency_hint,
     WebAudioDevice::RenderCallback* callback) {
-  // The |output_channels| does not exactly identify the channel layout of the
-  // device. The switch statement below assigns a best guess to the channel
-  // layout based on number of channels.
-  media::ChannelLayout layout = media::GuessChannelLayout(output_channels);
-  if (layout == media::CHANNEL_LAYOUT_UNSUPPORTED)
-    layout = media::CHANNEL_LAYOUT_DISCRETE;
+  // The `number_of_output_channels` does not manifest the actual channel
+  // layout of the audio output device. We use the best guess to the channel
+  // layout based on the number of channels.
+  media::ChannelLayout layout =
+      media::GuessChannelLayout(number_of_output_channels);
 
+  // Use "discrete" channel layout when the best guess was not successful.
+  if (layout == media::CHANNEL_LAYOUT_UNSUPPORTED) {
+    layout = media::CHANNEL_LAYOUT_DISCRETE;
+  }
+
+  // Using `UnguessableToken()` prevents from guessing the session ID to gain
+  // access to a capture stream.
   return RendererWebAudioDeviceImpl::Create(
-      layout, output_channels, latency_hint, callback,
-      /*session_id=*/base::UnguessableToken());
+      sink_descriptor, layout, number_of_output_channels, latency_hint,
+      callback, /*session_id=*/base::UnguessableToken());
 }
 
 bool RendererBlinkPlatformImpl::DecodeAudioFileData(
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h
index bb3be5a..78ffa14 100644
--- a/content/renderer/renderer_blink_platform_impl.h
+++ b/content/renderer/renderer_blink_platform_impl.h
@@ -116,7 +116,8 @@
   unsigned AudioHardwareOutputChannels() override;
   base::TimeDelta GetHungRendererDelay() override;
   std::unique_ptr<blink::WebAudioDevice> CreateAudioDevice(
-      unsigned output_channels,
+      const blink::WebAudioSinkDescriptor& sink_descriptor,
+      unsigned number_of_output_channels,
       const blink::WebAudioLatencyHint& latency_hint,
       blink::WebAudioDevice::RenderCallback* callback) override;
   bool DecodeAudioFileData(blink::WebAudioBus* destination_bus,
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
index ecba9e6..d3c3d86 100644
--- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -458,6 +458,8 @@
 crbug.com/1372144 [ android android-sm-a135m ] Pixel_CanvasLowLatencyWebGLAlphaFalse [ Failure ]
 crbug.com/1372141 [ android android-sm-a235m ] Pixel_CanvasLowLatencyWebGLAlphaFalse [ Failure ]
 
+crbug.com/1373965 [ fuchsia ] Pixel_VideoStreamFrom2DAlphaCanvas_DisableOOPRaster [ Failure ]
+
 #######################################################################
 # Automated Entries After This Point - Do Not Manually Add Below Here #
 #######################################################################
diff --git a/device/bluetooth/floss/bluetooth_adapter_floss.cc b/device/bluetooth/floss/bluetooth_adapter_floss.cc
index 16525c2..fc92c83 100644
--- a/device/bluetooth/floss/bluetooth_adapter_floss.cc
+++ b/device/bluetooth/floss/bluetooth_adapter_floss.cc
@@ -828,7 +828,8 @@
     std::unique_ptr<device::BluetoothAdvertisement::Data> advertisement_data,
     CreateAdvertisementCallback callback,
     AdvertisementErrorCallback error_callback) {
-  NOTIMPLEMENTED();
+  std::move(error_callback)
+      .Run(device::BluetoothAdvertisement::ERROR_UNSUPPORTED_PLATFORM);
 }
 
 void BluetoothAdapterFloss::SetAdvertisingInterval(
@@ -836,13 +837,15 @@
     const base::TimeDelta& max,
     base::OnceClosure callback,
     AdvertisementErrorCallback error_callback) {
-  NOTIMPLEMENTED();
+  std::move(error_callback)
+      .Run(device::BluetoothAdvertisement::ERROR_UNSUPPORTED_PLATFORM);
 }
 
 void BluetoothAdapterFloss::ResetAdvertising(
     base::OnceClosure callback,
     AdvertisementErrorCallback error_callback) {
-  NOTIMPLEMENTED();
+  std::move(error_callback)
+      .Run(device::BluetoothAdvertisement::ERROR_UNSUPPORTED_PLATFORM);
 }
 
 void BluetoothAdapterFloss::ConnectDevice(
diff --git a/device/bluetooth/floss/bluetooth_device_floss.cc b/device/bluetooth/floss/bluetooth_device_floss.cc
index f0b2a1a..5ce92fa3 100644
--- a/device/bluetooth/floss/bluetooth_device_floss.cc
+++ b/device/bluetooth/floss/bluetooth_device_floss.cc
@@ -474,11 +474,9 @@
 
 void BluetoothDeviceFloss::TriggerConnectCallback(
     absl::optional<BluetoothDevice::ConnectErrorCode> error_code) {
-  if (--num_connecting_calls_ == 0)
+  if (num_connecting_calls_ > 0 && --num_connecting_calls_ == 0)
     adapter_->NotifyDeviceChanged(this);
 
-  DCHECK(num_connecting_calls_ >= 0);
-
   if (pending_callback_on_connect_profiles_) {
     std::move(*pending_callback_on_connect_profiles_).Run(error_code);
     pending_callback_on_connect_profiles_ = absl::nullopt;
diff --git a/device/bluetooth/floss/bluetooth_device_floss.h b/device/bluetooth/floss/bluetooth_device_floss.h
index 0063ad8..76ae2634 100644
--- a/device/bluetooth/floss/bluetooth_device_floss.h
+++ b/device/bluetooth/floss/bluetooth_device_floss.h
@@ -181,7 +181,9 @@
   // This is used for determining if the device is paired.
   uint32_t connection_state_ = 0;
 
-  // Number of ongoing calls to Connect().
+  // Number of ongoing calls to Connect(). Incremented with a call to Connect()
+  // and decremented when either profiles are connected or pairing was
+  // cancelled.
   int num_connecting_calls_ = 0;
 
   // UI thread task runner and socket thread used to create sockets.
diff --git a/docs/history_manipulation_intervention.md b/docs/history_manipulation_intervention.md
new file mode 100644
index 0000000..54c8a97
--- /dev/null
+++ b/docs/history_manipulation_intervention.md
@@ -0,0 +1,65 @@
+# History manipulation intervention in Chromium
+
+Reference: [PSA on blink-dev](https://groups.google.com/a/chromium.org/g/blink-dev/c/T8d4_BRb2xQ/m/WSdOiOFcBAAJ)
+
+## Summary
+Some pages make it difficult or impossible for the user to use the browser back
+button to go back to the page they came from. Pages accomplish this using
+redirects or by manipulating the browser history, resulting in an
+abusive/annoying user experience.
+
+The history manipulation intervention mitigates such abuse by making the
+browser’s back button skip over pages that added history entries or redirected
+the user without ever getting a user activation. Note that the intervention only
+impacts the browser back/forward buttons and not the `history.back()/forward()`
+APIs.
+
+Here’s an example:
+1) User is on a.com and clicks to go to b.com
+2) b.com adds a history entry using `pushState` or navigates the user to another
+page (c.com) without ever getting a user activation.
+3) If the user presses back, the browser will skip b.com and go back to a.com
+instead.
+
+## Spec
+Because this only impacts browser UI, this is allowed by the spec, which only
+governs the behavior of `history.back/forward`.
+However, it might be good to spec this anyway, so that users get consistent
+experiences in all browsers. That work is tracked at
+https://github.com/whatwg/html/issues/7832
+
+## Invariants
+The intervention guarantees the following invariants:
+1. Only back/forward navigations triggered by the back/forward buttons will ever
+   skip history entries. This ensures that the history API's behavior is
+   unaffected.
+2. The intervention marks a history entry as skippable if the document creates
+   another history entry without a user activation.
+3. If a document receives a user activation (before or after creating history
+   entries), its history entry is not skippable. With an activation, the
+   document can create many unskippable same-document history entries, until
+   either a cross-document navigation or a back/forward occurs.
+4. All same-document history entries will have the same skippable state. When
+   marking an entry unskippable after a user activation, this ensures that the
+   rest of the document's entries work as well. When marking an entry as
+   skippable, this ensures that all entries for the offending document will be
+   skipped.
+5. Revisiting a skippable history entry does not change its skippable status,
+   unless it receives a user activation. This ensures that history.back() will
+   not bypass the intervention, per https://crbug.com/1121293.
+6. The intervention applies to history entries created by subframes as well. A
+   user activation on any frame on the page is sufficient to make the entry
+   unskippable, per https://crbug.com/953056.
+
+## Details
+1. The intervention works by setting the `should_skip_on_back_forward_ui_`
+   member for a `NavigationEntryImpl` object. The member is initially set to
+   false, and it is set to true if any document in the page adds a history entry
+   without having a user activation.
+2. `NavigationController::CanGoBack()` will return false if all entries are
+   marked to be skipped on back/forward UI. On desktop this leads to the back
+   button being disabled. On Android, pressing the back button will close the
+   current tab and a previous tab could be shown as it would normally happen on
+   Android when the back button is pressed from the first entry of a tab.
+3. The oldest `NavigationEntryImpl` that is marked as skippable is the one
+   that is pruned if max entry count is reached.
diff --git a/infra/config/generated/builders/ci/chromeos-amd64-generic-rel/properties.json b/infra/config/generated/builders/ci/chromeos-amd64-generic-rel/properties.json
index bf892a2..e00afc7 100644
--- a/infra/config/generated/builders/ci/chromeos-amd64-generic-rel/properties.json
+++ b/infra/config/generated/builders/ci/chromeos-amd64-generic-rel/properties.json
@@ -24,11 +24,15 @@
                 ],
                 "target_arch": "intel",
                 "target_bits": 64,
+                "target_cros_boards": [
+                  "amd64-generic"
+                ],
                 "target_platform": "chromeos"
               },
               "legacy_gclient_config": {
                 "apply_configs": [
-                  "chromeos"
+                  "chromeos",
+                  "checkout_lacros_sdk"
                 ],
                 "config": "chromium"
               }
diff --git a/infra/config/generated/builders/goma/chromeos-amd64-generic-rel-goma-rbe-canary/properties.json b/infra/config/generated/builders/goma/chromeos-amd64-generic-rel-goma-rbe-canary/properties.json
index cdcc36d8..e85f3a2 100644
--- a/infra/config/generated/builders/goma/chromeos-amd64-generic-rel-goma-rbe-canary/properties.json
+++ b/infra/config/generated/builders/goma/chromeos-amd64-generic-rel-goma-rbe-canary/properties.json
@@ -25,11 +25,15 @@
                 ],
                 "target_arch": "intel",
                 "target_bits": 64,
+                "target_cros_boards": [
+                  "amd64-generic"
+                ],
                 "target_platform": "chromeos"
               },
               "legacy_gclient_config": {
                 "apply_configs": [
-                  "chromeos"
+                  "chromeos",
+                  "checkout_lacros_sdk"
                 ],
                 "config": "chromium"
               }
diff --git a/infra/config/generated/builders/goma/chromeos-amd64-generic-rel-goma-rbe-latest/properties.json b/infra/config/generated/builders/goma/chromeos-amd64-generic-rel-goma-rbe-latest/properties.json
index a86f6481..6173da7f 100644
--- a/infra/config/generated/builders/goma/chromeos-amd64-generic-rel-goma-rbe-latest/properties.json
+++ b/infra/config/generated/builders/goma/chromeos-amd64-generic-rel-goma-rbe-latest/properties.json
@@ -25,11 +25,15 @@
                 ],
                 "target_arch": "intel",
                 "target_bits": 64,
+                "target_cros_boards": [
+                  "amd64-generic"
+                ],
                 "target_platform": "chromeos"
               },
               "legacy_gclient_config": {
                 "apply_configs": [
-                  "chromeos"
+                  "chromeos",
+                  "checkout_lacros_sdk"
                 ],
                 "config": "chromium"
               }
diff --git a/infra/config/generated/builders/goma/chromeos-amd64-generic-rel-goma-rbe-staging/properties.json b/infra/config/generated/builders/goma/chromeos-amd64-generic-rel-goma-rbe-staging/properties.json
index f77e9e2..0ffeb4c 100644
--- a/infra/config/generated/builders/goma/chromeos-amd64-generic-rel-goma-rbe-staging/properties.json
+++ b/infra/config/generated/builders/goma/chromeos-amd64-generic-rel-goma-rbe-staging/properties.json
@@ -24,11 +24,15 @@
                 ],
                 "target_arch": "intel",
                 "target_bits": 64,
+                "target_cros_boards": [
+                  "amd64-generic"
+                ],
                 "target_platform": "chromeos"
               },
               "legacy_gclient_config": {
                 "apply_configs": [
-                  "chromeos"
+                  "chromeos",
+                  "checkout_lacros_sdk"
                 ],
                 "config": "chromium"
               }
diff --git a/infra/config/generated/builders/goma/chromeos-amd64-generic-rel-goma-rbe-tot/properties.json b/infra/config/generated/builders/goma/chromeos-amd64-generic-rel-goma-rbe-tot/properties.json
index e71328f..0507c33d 100644
--- a/infra/config/generated/builders/goma/chromeos-amd64-generic-rel-goma-rbe-tot/properties.json
+++ b/infra/config/generated/builders/goma/chromeos-amd64-generic-rel-goma-rbe-tot/properties.json
@@ -25,11 +25,15 @@
                 ],
                 "target_arch": "intel",
                 "target_bits": 64,
+                "target_cros_boards": [
+                  "amd64-generic"
+                ],
                 "target_platform": "chromeos"
               },
               "legacy_gclient_config": {
                 "apply_configs": [
-                  "chromeos"
+                  "chromeos",
+                  "checkout_lacros_sdk"
                 ],
                 "config": "chromium"
               }
diff --git a/infra/config/generated/builders/try/chromeos-amd64-generic-rel-compilator/properties.json b/infra/config/generated/builders/try/chromeos-amd64-generic-rel-compilator/properties.json
index e27f6ac2..88c873f 100644
--- a/infra/config/generated/builders/try/chromeos-amd64-generic-rel-compilator/properties.json
+++ b/infra/config/generated/builders/try/chromeos-amd64-generic-rel-compilator/properties.json
@@ -24,11 +24,15 @@
                 ],
                 "target_arch": "intel",
                 "target_bits": 64,
+                "target_cros_boards": [
+                  "amd64-generic"
+                ],
                 "target_platform": "chromeos"
               },
               "legacy_gclient_config": {
                 "apply_configs": [
-                  "chromeos"
+                  "chromeos",
+                  "checkout_lacros_sdk"
                 ],
                 "config": "chromium"
               }
diff --git a/infra/config/generated/builders/try/chromeos-amd64-generic-rel/properties.json b/infra/config/generated/builders/try/chromeos-amd64-generic-rel/properties.json
index b998d0a..a35b81b 100644
--- a/infra/config/generated/builders/try/chromeos-amd64-generic-rel/properties.json
+++ b/infra/config/generated/builders/try/chromeos-amd64-generic-rel/properties.json
@@ -28,11 +28,15 @@
                 ],
                 "target_arch": "intel",
                 "target_bits": 64,
+                "target_cros_boards": [
+                  "amd64-generic"
+                ],
                 "target_platform": "chromeos"
               },
               "legacy_gclient_config": {
                 "apply_configs": [
-                  "chromeos"
+                  "chromeos",
+                  "checkout_lacros_sdk"
                 ],
                 "config": "chromium"
               }
diff --git a/infra/config/subprojects/chromium/ci/chromium.chromiumos.star b/infra/config/subprojects/chromium/ci/chromium.chromiumos.star
index 7219d1e..17819ea 100644
--- a/infra/config/subprojects/chromium/ci/chromium.chromiumos.star
+++ b/infra/config/subprojects/chromium/ci/chromium.chromiumos.star
@@ -258,12 +258,15 @@
             build_config = builder_config.build_config.RELEASE,
             target_arch = builder_config.target_arch.INTEL,
             target_bits = 64,
+            target_cros_boards = [
+                "amd64-generic",
+            ],
             target_platform = builder_config.target_platform.CHROMEOS,
             cros_boards_with_qemu_images = "amd64-generic-vm",
         ),
         gclient_config = builder_config.gclient_config(
             config = "chromium",
-            apply_configs = ["chromeos"],
+            apply_configs = ["chromeos", "checkout_lacros_sdk"],
         ),
     ),
     console_view_entry = consoles.console_view_entry(
diff --git a/ios/chrome/browser/ntp/features.h b/ios/chrome/browser/ntp/features.h
index cdbcdc7..fd04f91 100644
--- a/ios/chrome/browser/ntp/features.h
+++ b/ios/chrome/browser/ntp/features.h
@@ -54,6 +54,9 @@
 // buildflag is not defined.
 bool IsFeedBackgroundRefreshEnabled();
 
+// Whether Good Visits metric logging is enabled.
+bool IsGoodVisitsMetricEnabled();
+
 // Saves the current value for feature `kEnableFeedBackgroundRefresh`. This call
 // DCHECKs on the availability of `base::FeatureList`.
 void SaveFeedBackgroundRefreshEnabledForNextColdStart();
diff --git a/ios/chrome/browser/ntp/features.mm b/ios/chrome/browser/ntp/features.mm
index 6a2ae2a..2ee3bb8 100644
--- a/ios/chrome/browser/ntp/features.mm
+++ b/ios/chrome/browser/ntp/features.mm
@@ -28,6 +28,10 @@
              "CreateDiscoverFeedServiceEarly",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kEnableGoodVisitsMetric,
+             "EnableGoodVisitsMetric",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
 // Key for NSUserDefaults containing a bool indicating whether the next run
 // should enable feed backround refresh. This is used because registering for
 // background refreshes must happen early in app initialization and FeatureList
@@ -58,6 +62,10 @@
   return base::FeatureList::IsEnabled(kCreateDiscoverFeedServiceEarly);
 }
 
+bool IsGoodVisitsMetricEnabled() {
+  return base::FeatureList::IsEnabled(kEnableGoodVisitsMetric);
+}
+
 bool IsFeedBackgroundRefreshEnabled() {
 #if !BUILDFLAG(IOS_BACKGROUND_MODE_ENABLED)
   return false;
diff --git a/ios/chrome/browser/ui/ntp/metrics/BUILD.gn b/ios/chrome/browser/ui/ntp/metrics/BUILD.gn
index 103ed403..cf4385f 100644
--- a/ios/chrome/browser/ui/ntp/metrics/BUILD.gn
+++ b/ios/chrome/browser/ui/ntp/metrics/BUILD.gn
@@ -22,6 +22,7 @@
     "//components/ntp_tiles",
     "//ios/chrome/browser",
     "//ios/chrome/browser/discover_feed:constants",
+    "//ios/chrome/browser/ntp:features",
     "//ios/chrome/browser/ui/content_suggestions:metrics",
     "//ios/chrome/browser/ui/favicon",
     "//ios/chrome/browser/ui/ntp",
diff --git a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.h b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.h
index dbee803..748ec93 100644
--- a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.h
+++ b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.h
@@ -16,12 +16,24 @@
 // scrolling.
 extern const int kMinScrollThreshold;
 
+// Time spent by the user in feed to consider it a
+// FeedEngagementType::kFeedGoodVisit.
+extern const int kGoodVisitTimeInFeedSeconds;
+
+// Minimum time spent in an article to be considered a non-short click. A
+// non-short click is any click on an article lasting more than the value
+// assigned to this constant. Calculated when back in the feed.
+extern const int kNonShortClickSeconds;
+
 // Time between two metrics recorded to consider it a new session.
 extern const int kMinutesBetweenSessions;
 
 // The max amount of cards in the Discover Feed.
 extern const int kMaxCardsInFeed;
 
+// Stores the time when the user visits an article on the feed.
+extern NSString* const kArticleClickTimestampKey;
+
 #pragma mark - Enums
 
 // DO NOT CHANGE. Values are from enums.xml representing what could be broken in
diff --git a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.mm b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.mm
index 226e89d8..f0f6fe2 100644
--- a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.mm
+++ b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.mm
@@ -9,9 +9,13 @@
 #endif
 
 const int kMinScrollThreshold = 140;
+const int kGoodVisitTimeInFeedSeconds = 60;
+const int kNonShortClickSeconds = 10;
 const int kMinutesBetweenSessions = 5;
 const int kMaxCardsInFeed = 50;
 
+NSString* const kArticleClickTimestampKey = @"ShortClickInteractionTimestamp";
+
 #pragma mark - Histograms
 
 const char kDiscoverFeedUserActionHistogram[] =
diff --git a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.h b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.h
index c6dc4dab..496585f 100644
--- a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.h
+++ b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.h
@@ -37,6 +37,9 @@
 // visible.
 - (void)recordDeviceOrientationChanged:(UIDeviceOrientation)orientation;
 
+// Record when the NTP was is displayed.
+- (void)recordNTPBecameVisible;
+
 // Record metrics for when the user has tapped on the feed preview.
 - (void)recordDiscoverFeedPreviewTapped;
 
diff --git a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.mm b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.mm
index 85117ffc..7e91bcf 100644
--- a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.mm
+++ b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.mm
@@ -11,6 +11,7 @@
 #import "base/metrics/user_metrics_action.h"
 #import "base/time/time.h"
 #import "components/feed/core/v2/public/common_enums.h"
+#import "ios/chrome/browser/ntp/features.h"
 #import "ios/chrome/browser/ui/content_suggestions/ntp_home_metrics.h"
 #import "ios/chrome/browser/ui/ntp/feed_control_delegate.h"
 #import "ios/chrome/browser/ui/ntp/metrics/feed_session_recorder.h"
@@ -38,9 +39,16 @@
 // FeedEngagementType::kFeedScrolled.
 @property(nonatomic, assign) BOOL scrolledReportedDiscover;
 @property(nonatomic, assign) BOOL scrolledReportedFollowing;
+// Tracking property to avoid duplicate recordings of
+// FeedEngagementType::kGoodVisit.
+@property(nonatomic, assign) BOOL goodVisitReported;
+
 // The time when the first metric is being recorded for this session.
 @property(nonatomic, assign) base::Time sessionStartTime;
 
+// The time when the first GoodVisit metric is being recorded for this session.
+@property(nonatomic, assign) base::Time goodVisitSessionStartTime;
+
 @end
 
 @implementation FeedMetricsRecorder
@@ -59,6 +67,10 @@
 - (void)recordFeedScrolled:(int)scrollDistance {
   [self recordEngagement:scrollDistance interacted:NO];
 
+  if (IsGoodVisitsMetricEnabled()) {
+    [self recordEngagementGoodVisit:scrollDistance interacted:NO];
+  }
+
   // If neither feed has been scrolled into, log "AllFeeds" scrolled.
   if (!self.scrolledReportedDiscover && !self.scrolledReportedFollowing) {
     UMA_HISTOGRAM_ENUMERATION(kAllFeedsEngagementTypeHistogram,
@@ -93,6 +105,40 @@
   }
 }
 
+// Triggered when the NTP becomes visible.
+- (void)recordNTPBecameVisible {
+  // Checks if there is a timestamp in defaults for when a user clicked
+  // on an article.
+  // Calls recordEngagementGoodVisit for a possible non-short click
+  // interaction.
+  if (IsGoodVisitsMetricEnabled()) {
+    return;
+  }
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+  NSDate* shortClickVisitStart = base::mac::ObjCCast<NSDate>(
+      [defaults objectForKey:kArticleClickTimestampKey]);
+
+  base::TimeDelta nonShortClickThreshold = base::Seconds(kNonShortClickSeconds);
+
+  // Check if kArticleClickTimestamp exists. If it does, check delta. If it
+  // doesn't ignore.
+  // It basically checks the non-short click condition in this method.
+  if (shortClickVisitStart) {
+    base::Time shortClickVisitStartTime =
+        base::Time::FromNSDate(shortClickVisitStart);
+    NSDate* shortClickVisitEnd = [[NSDate alloc] init];
+    base::Time shortClickVisitEndTime =
+        base::Time::FromNSDate(shortClickVisitEnd);
+
+    if (shortClickVisitEndTime - shortClickVisitStartTime >
+        nonShortClickThreshold) {
+      [self recordEngagedGoodVisits];
+    }
+    // Clean defaults for new session
+    [defaults setObject:nil forKey:kArticleClickTimestampKey];
+  }
+}
+
 - (void)recordDiscoverFeedPreviewTapped {
   [self recordDiscoverFeedUserActionHistogram:FeedUserActionType::
                                                   kTappedDiscoverFeedPreview
@@ -668,6 +714,24 @@
   if (isInteraction) {
     [self recordInteraction];
   }
+
+  // Check if actionType warrants a Good Explicit Visit
+  // If actionType is any of the cases below, trigger a Good Explicit
+  // interaction by calling recordEngagementGoodVisit
+  if (IsGoodVisitsMetricEnabled()) {
+    return;
+  }
+  switch (actionType) {
+    case FeedUserActionType::kAddedToReadLater:
+    case FeedUserActionType::kOpenedNativeContextMenu:
+    case FeedUserActionType::kTappedOpenInNewIncognitoTab:
+      [self recordEngagementGoodVisit:0 interacted:YES];
+      break;
+    // Default will handle the remaining FeedUserActionTypes that
+    // do not trigger a Good Explicit interaction.
+    default:
+      break;
+  }
 }
 
 // Records Feed engagement.
@@ -680,6 +744,7 @@
   if (now - self.sessionStartTime > visitTimeout) {
     [self finalizeSession];
   }
+
   // Reset the last active time for session measurement.
   self.sessionStartTime = now;
 
@@ -700,10 +765,48 @@
   [self.sessionRecorder recordUserInteractionOrScrolling];
 }
 
+// Records a Good Visit whether from a scroll or interaction.
+- (void)recordEngagementGoodVisit:(int)scrollDistance
+                       interacted:(BOOL)interacted {
+  DCHECK(IsGoodVisitsMetricEnabled());
+  // Determine if this interaction is part of a new 'session'.
+  base::Time now = base::Time::Now();
+  base::TimeDelta goodVisitSessionTimeout =
+      base::Minutes(kMinutesBetweenSessions);
+  base::TimeDelta goodVisitMinimumTimeInFeed =
+      base::Minutes(kGoodVisitTimeInFeedSeconds);
+
+  // Check if session has been started. If it has, it can only reset when
+  // a Good Visit session is terminated.
+  if (self.goodVisitSessionStartTime.is_null()) {
+    self.goodVisitSessionStartTime = now;
+  }
+
+  // Delta between now and session start time.
+  base::TimeDelta timeDifferential = now - self.goodVisitSessionStartTime;
+
+  if (timeDifferential > goodVisitSessionTimeout) {
+    [self finalizeSessionGoodVisits];
+    // Session resets when you finalize the session
+    self.goodVisitSessionStartTime = now;
+  }
+
+  // Report the user as engaged-good-visits if they have had one of these:
+  // 1. "Non-short click" (calls recordEngagedGoodVisits directly)
+  // 2. Good Explicit Interaction (add to reading list, long press
+  //  open in new incognito tab ...)
+  // 3. Good time in feed ( > 60 seconds with >= 1 scroll (distance > 0))
+  // Then if the visit has not been logged, will log visit as a good visit.
+
+  if (interacted ||
+      (timeDifferential > goodVisitMinimumTimeInFeed && scrollDistance > 0)) {
+    [self recordEngagedGoodVisits];
+  }
+}
+
 // Records any direct interaction with the Feed, this doesn't include scrolling.
 - (void)recordInteraction {
   [self recordEngagement:0 interacted:YES];
-
   // Log interaction for all feeds
   UMA_HISTOGRAM_ENUMERATION(kAllFeedsEngagementTypeHistogram,
                             FeedEngagementType::kFeedInteracted);
@@ -790,8 +893,24 @@
   base::RecordAction(base::UserMetricsAction(kDiscoverFeedUserActionEngaged));
 }
 
+// Records Good Visits for both the Following and Discover feed.
+- (void)recordEngagedGoodVisits {
+  // Check if the user has previously engaged with the feed in the same
+  // session.
+  // If neither feed has been engaged with, log "AllFeeds" engagement.
+  DCHECK(IsGoodVisitsMetricEnabled());
+  if (!self.goodVisitReported) {
+    UMA_HISTOGRAM_ENUMERATION(kAllFeedsEngagementTypeHistogram,
+                              FeedEngagementType::kGoodVisit);
+    self.goodVisitReported = YES;
+  }
+
+  // TODO(crbug.com/1373650): Implement separate feed logging for
+  // Good Visits.
+}
+
 // Resets the session tracking values, this occurs if there's been
-// kMinutesBetweenSessions minutes between sessions.
+// `kMinutesBetweenSessions` minutes between sessions.
 - (void)finalizeSession {
   // If simple engagement hasn't been logged, then there's no session to
   // finalize.
@@ -810,6 +929,16 @@
   self.scrolledReportedFollowing = NO;
 }
 
+// Resets the Good Visits session tracking values, this occurs if there's been
+// kMinutesBetweenSessions minutes between sessions.
+- (void)finalizeSessionGoodVisits {
+  // Clean defaults for new session.
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+  [defaults setObject:nil forKey:kArticleClickTimestampKey];
+
+  self.goodVisitReported = NO;
+}
+
 // Records the `duration` it took to Discover feed to perform any
 // network operation.
 - (void)recordNetworkRequestDuration:(base::TimeDelta)duration {
@@ -819,6 +948,13 @@
 // Records that a URL was opened regardless of the target surface (e.g. New Tab,
 // Same Tab, Incognito Tab, etc.)
 - (void)recordOpenURL {
+  // Save the time of the open so we can then calculate how long the user spent
+  // in that page.
+  NSDate* shortClickVisitStartTime = [[NSDate alloc] init];
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+  [defaults setObject:shortClickVisitStartTime
+               forKey:kArticleClickTimestampKey];
+
   if (self.isShownOnStartSurface) {
     UMA_HISTOGRAM_ENUMERATION(kActionOnStartSurface,
                               IOSContentSuggestionsActionType::kFeedCard);
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
index f258892..2f8068439f 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
@@ -453,6 +453,7 @@
         self.feedMetricsRecorder.feedControlDelegate = self;
         self.feedMetricsRecorder.followDelegate = self;
       }
+      [self.feedMetricsRecorder recordNTPBecameVisible];
     }
     if (!visible) {
       // Unfocus omnibox, to prevent it from lingering when it should be
diff --git a/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc b/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
index 7c64ff6..9401d60 100644
--- a/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
+++ b/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
@@ -12,6 +12,7 @@
 #include <utility>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/files/file.h"
@@ -33,6 +34,7 @@
 #include "media/capture/video/chromeos/mojom/camera_common.mojom.h"
 #include "media/capture/video/chromeos/mojom/cros_camera_client.mojom.h"
 #include "media/capture/video/chromeos/mojom/cros_camera_service.mojom.h"
+#include "media/capture/video/chromeos/mojom/effects_pipeline.mojom.h"
 #include "media/capture/video/chromeos/video_capture_features_chromeos.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/platform/named_platform_channel.h"
@@ -127,6 +129,36 @@
   mojo::Remote<cros::mojom::CameraHalClient> client_;
 };
 
+cros::mojom::EffectsConfigPtr GetCameraEffectState() {
+  cros::mojom::EffectsConfigPtr effects_state =
+      cros::mojom::EffectsConfig::New();
+
+  std::string blur_level = GetFieldTrialParamValueByFeature(
+      ash::features::kVCBackgroundBlur, "blur_level");
+  if (blur_level == "lowest") {
+    effects_state->blur_level = cros::mojom::BlurLevel::kLowest;
+  } else if (blur_level == "light") {
+    effects_state->blur_level = cros::mojom::BlurLevel::kLight;
+  } else if (blur_level == "medium") {
+    effects_state->blur_level = cros::mojom::BlurLevel::kMedium;
+  } else if (blur_level == "heavy") {
+    effects_state->blur_level = cros::mojom::BlurLevel::kHeavy;
+  } else if (blur_level == "maximum") {
+    effects_state->blur_level = cros::mojom::BlurLevel::kMaximum;
+  }
+
+  effects_state->effect = ash::features::IsVCBackgroundBlurEnabled()
+                              ? cros::mojom::CameraEffect::kBackgroundBlur
+                              : cros::mojom::CameraEffect::kNone;
+  effects_state->effect = ash::features::IsVCBackgroundReplaceEnabled()
+                              ? cros::mojom::CameraEffect::kBackgroundReplace
+                              : effects_state->effect;
+  effects_state->effect = ash::features::IsVCPortraitRelightingEnabled()
+                              ? cros::mojom::CameraEffect::kPortraitRelight
+                              : effects_state->effect;
+  return effects_state;
+}
+
 }  // namespace
 
 CameraClientObserver::~CameraClientObserver() = default;
@@ -279,21 +311,11 @@
     if (!base::DeleteFile(disable_file_path)) {
       LOG(WARNING) << "Could not delete " << kForceDisableEffectsPath;
     }
-    const base::CommandLine* command_line =
-        base::CommandLine::ForCurrentProcess();
-    if (command_line->HasSwitch(media::switches::kEffectsOverride)) {
-      std::string value =
-          command_line->GetSwitchValueASCII(switches::kEffectsOverride);
-      if (value == switches::kEffectsForceEnabled) {
-        base::File file(enable_file_path, base::File::FLAG_CREATE_ALWAYS |
-                                              base::File::FLAG_WRITE);
-        file.Close();
-      } else if (value == switches::kEffectsForceDisabled) {
-        base::File file(disable_file_path, base::File::FLAG_CREATE_ALWAYS |
-                                               base::File::FLAG_WRITE);
-        file.Close();
-      }
-    }
+    base::File file(ash::features::IsVCBackgroundBlurEnabled()
+                        ? enable_file_path
+                        : disable_file_path,
+                    base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
+    file.Close();
   }
 
   jda_factory_ = std::move(jda_factory);
@@ -476,6 +498,12 @@
         std::move(auto_framing_supported_callback_));
   }
   camera_hal_server_->SetAutoFramingState(current_auto_framing_state_);
+  camera_hal_server_->SetCameraEffect(
+      GetCameraEffectState(),
+      base::BindOnce([](cros::mojom::SetEffectResult result) {
+        if (result == cros::mojom::SetEffectResult::kError)
+          LOG(ERROR) << "SetCameraEffect failed.";
+      }));
   CAMERA_LOG(EVENT) << "Camera HAL server registered";
   std::move(callback).Run(
       0, camera_hal_server_callbacks_.BindNewPipeAndPassRemote());
diff --git a/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc b/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc
index 71c350d..e4d61ea 100644
--- a/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc
+++ b/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc
@@ -16,6 +16,7 @@
 #include "media/capture/video/chromeos/mojom/camera_common.mojom.h"
 #include "media/capture/video/chromeos/mojom/cros_camera_client.mojom.h"
 #include "media/capture/video/chromeos/mojom/cros_camera_service.mojom.h"
+#include "media/capture/video/chromeos/mojom/effects_pipeline.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
@@ -42,6 +43,12 @@
       cros::mojom::CameraClientType camera_client_type) override {
     DoCreateChannel(std::move(camera_module_receiver), camera_client_type);
   }
+
+  // **NOTE**: If you add additional mocks here, you will need to
+  //           carefully add an EXPECT_CALL with a WillOnce to invoke
+  //           CameraHalDispatcherImplTest::QuitRunLoop and increment
+  //           RunLoop(val) appropriately. Failing to do this will
+  //           introduce flakiness into these tests.
   MOCK_METHOD2(DoCreateChannel,
                void(mojo::PendingReceiver<cros::mojom::CameraModule>
                         camera_module_receiver,
@@ -58,6 +65,11 @@
                void(cros::mojom::CameraPrivacySwitchState state));
   MOCK_METHOD1(GetAutoFramingSupported,
                void(GetAutoFramingSupportedCallback callback));
+  MOCK_METHOD2(SetCameraEffect,
+               void(::cros::mojom::EffectsConfigPtr config,
+                    SetCameraEffectCallback callback));
+  // **NOTE**: Please read the note at the top of these mocks if you're
+  //           adding more mocks.
 
   mojo::PendingRemote<cros::mojom::CameraHalServer> GetPendingRemote() {
     return receiver_.BindNewPipeAndPassRemote();
@@ -212,6 +224,17 @@
       .Times(1)
       .WillOnce(
           InvokeWithoutArgs(this, &CameraHalDispatcherImplTest::QuitRunLoop));
+  EXPECT_CALL(*mock_server, SetAutoFramingState(_))
+      .Times(1)
+      .WillOnce(
+          InvokeWithoutArgs(this, &CameraHalDispatcherImplTest::QuitRunLoop));
+  EXPECT_CALL(*mock_server, SetCameraEffect(_, _))
+      .Times(1)
+      .WillOnce([this](::cros::mojom::EffectsConfigPtr,
+                       MockCameraHalServer::SetCameraEffectCallback callback) {
+        std::move(callback).Run(::cros::mojom::SetEffectResult::kOk);
+        this->QuitRunLoop();
+      });
 
   auto server = mock_server->GetPendingRemote();
   GetProxyTaskRunner()->PostTask(
@@ -232,8 +255,9 @@
           base::BindOnce(&CameraHalDispatcherImplTest::OnRegisteredClient,
                          base::Unretained(this))));
 
-  // Wait until the client gets the established Mojo channel.
-  DoLoop(2);
+  // Wait until the client gets the established Mojo channel, and that
+  // all expected mojo calls have been invoked.
+  DoLoop(4);
 
   // The client registration callback may be called after
   // CameraHalClient::SetUpChannel(). Use a waitable event to make sure we have
@@ -254,6 +278,17 @@
       .Times(1)
       .WillOnce(
           InvokeWithoutArgs(this, &CameraHalDispatcherImplTest::QuitRunLoop));
+  EXPECT_CALL(*mock_server, SetAutoFramingState(_))
+      .Times(1)
+      .WillOnce(
+          InvokeWithoutArgs(this, &CameraHalDispatcherImplTest::QuitRunLoop));
+  EXPECT_CALL(*mock_server, SetCameraEffect(_, _))
+      .Times(1)
+      .WillOnce([this](::cros::mojom::EffectsConfigPtr,
+                       MockCameraHalServer::SetCameraEffectCallback callback) {
+        std::move(callback).Run(::cros::mojom::SetEffectResult::kOk);
+        this->QuitRunLoop();
+      });
 
   server = mock_server->GetPendingRemote();
   GetProxyTaskRunner()->PostTask(
@@ -264,8 +299,9 @@
           base::BindOnce(&CameraHalDispatcherImplTest::OnRegisteredServer,
                          base::Unretained(this))));
 
-  // Wait until the clients get the newly established Mojo channel.
-  DoLoop(2);
+  // Wait until the client gets the established Mojo channel, and that
+  // all expected mojo calls have been invoked.
+  DoLoop(4);
 }
 
 // Test that the CameraHalDisptcherImpl correctly re-establishes a Mojo channel
@@ -284,6 +320,17 @@
       .Times(1)
       .WillOnce(
           InvokeWithoutArgs(this, &CameraHalDispatcherImplTest::QuitRunLoop));
+  EXPECT_CALL(*mock_server, SetAutoFramingState(_))
+      .Times(1)
+      .WillOnce(
+          InvokeWithoutArgs(this, &CameraHalDispatcherImplTest::QuitRunLoop));
+  EXPECT_CALL(*mock_server, SetCameraEffect(_, _))
+      .Times(1)
+      .WillOnce([this](::cros::mojom::EffectsConfigPtr,
+                       MockCameraHalServer::SetCameraEffectCallback callback) {
+        std::move(callback).Run(::cros::mojom::SetEffectResult::kOk);
+        this->QuitRunLoop();
+      });
 
   auto server = mock_server->GetPendingRemote();
   GetProxyTaskRunner()->PostTask(
@@ -304,8 +351,9 @@
           base::BindOnce(&CameraHalDispatcherImplTest::OnRegisteredClient,
                          base::Unretained(this))));
 
-  // Wait until the client gets the established Mojo channel.
-  DoLoop(2);
+  // Wait until the client gets the established Mojo channel, and that
+  // all expected mojo calls have been invoked.
+  DoLoop(4);
 
   // The client registration callback may be called after
   // CameraHalClient::SetUpChannel(). Use a waitable event to make sure we have
@@ -338,7 +386,8 @@
           base::BindOnce(&CameraHalDispatcherImplTest::OnRegisteredClient,
                          base::Unretained(this))));
 
-  // Wait until the clients gets the newly established Mojo channel.
+  // Wait until the clients gets the newly established Mojo channel, and that
+  // all expected mojo calls have been invoked.
   DoLoop(2);
 
   // Make sure the client is still successfully registered.
@@ -362,6 +411,7 @@
           base::BindOnce(&CameraHalDispatcherImplTest::OnRegisteredServer,
                          base::Unretained(this))));
 
+  bool firstRun = true;
   for (auto type : TokenManager::kTrustedClientTypes) {
     auto mock_client = std::make_unique<MockCameraHalClient>();
     EXPECT_CALL(*mock_server, DoCreateChannel(_, _))
@@ -372,6 +422,22 @@
         .Times(1)
         .WillOnce(
             InvokeWithoutArgs(this, &CameraHalDispatcherImplTest::QuitRunLoop));
+    if (firstRun) {
+      EXPECT_CALL(*mock_server, SetAutoFramingState(_))
+          .Times(1)
+          .WillOnce(InvokeWithoutArgs(
+              this, &CameraHalDispatcherImplTest::QuitRunLoop));
+      EXPECT_CALL(*mock_server, SetCameraEffect(_, _))
+          .Times(1)
+          .WillOnce(
+              [this](::cros::mojom::EffectsConfigPtr,
+                     MockCameraHalServer::SetCameraEffectCallback callback) {
+                std::move(callback).Run(::cros::mojom::SetEffectResult::kOk);
+                this->QuitRunLoop();
+              });
+      // These above calls only happen on the first client connection
+      DoLoop(2);
+    }
 
     auto client = mock_client->GetPendingRemote();
     GetProxyTaskRunner()->PostTask(
@@ -391,6 +457,7 @@
     // have the result.
     register_client_event_.Wait();
     ASSERT_EQ(last_register_client_result_, 0);
+    firstRun = false;
   }
 }
 
diff --git a/media/capture/video/chromeos/mojom/BUILD.gn b/media/capture/video/chromeos/mojom/BUILD.gn
index 8fbc22f..f4889ad 100644
--- a/media/capture/video/chromeos/mojom/BUILD.gn
+++ b/media/capture/video/chromeos/mojom/BUILD.gn
@@ -25,6 +25,7 @@
   sources = [
     "cros_camera_client.mojom",
     "cros_camera_service.mojom",
+    "effects_pipeline.mojom",
   ]
 
   deps = [
diff --git a/media/capture/video/chromeos/mojom/cros_camera_service.mojom b/media/capture/video/chromeos/mojom/cros_camera_service.mojom
index d497d30..1b8e3759c 100644
--- a/media/capture/video/chromeos/mojom/cros_camera_service.mojom
+++ b/media/capture/video/chromeos/mojom/cros_camera_service.mojom
@@ -11,6 +11,7 @@
 import "components/chromeos_camera/common/mjpeg_decode_accelerator.mojom";
 import "media/capture/video/chromeos/mojom/camera_common.mojom";
 import "media/capture/video/chromeos/mojom/cros_camera_client.mojom";
+import "media/capture/video/chromeos/mojom/effects_pipeline.mojom";
 import "mojo/public/mojom/base/unguessable_token.mojom";
 
 // CameraClientType indicates the type of a CameraHalClient.
@@ -120,7 +121,7 @@
 
 // The CrOS camera HAL v3 Mojo server.
 //
-// Next method ID: 6
+// Next method ID: 7
 interface CameraHalServer {
   // A caller calls CreateChannel to create a new Mojo channel to the camera
   // HAL v3 adapter.  Upon successfully binding of |camera_module_receiver|, the
@@ -148,6 +149,10 @@
   // Get if the HAL supports auto framing.
   [MinVersion=9]
   GetAutoFramingSupported@5() => (bool supported);
+
+  // Turn ON/OFF and configure specified effect.
+  [MinVersion=10]
+  SetCameraEffect@6(EffectsConfig config) => (SetEffectResult result);
 };
 
 // CameraHalServerCallbacks is an interface for CameraHalServer to notify
diff --git a/media/capture/video/chromeos/mojom/effects_pipeline.mojom b/media/capture/video/chromeos/mojom/effects_pipeline.mojom
new file mode 100644
index 0000000..ebd04709
--- /dev/null
+++ b/media/capture/video/chromeos/mojom/effects_pipeline.mojom
@@ -0,0 +1,60 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Next min version: 1
+
+module cros.mojom;
+
+// Set of effects that can be enabled.
+// Used by EffectsConfig to indicate which effect the g3 shared library
+// should be applying. Needs to be kept in sync with g3 version found in
+// chromeos/ml/effects_pipeline/effects_config.h
+[Extensible]
+enum CameraEffect {
+  [Default] kNone = 0,
+  kBackgroundBlur = 1,
+  kBackgroundReplace = 2,
+  kPortraitRelight = 3,
+};
+
+// Set of GPU APIs available.
+[Extensible]
+enum GpuApi {
+  kOpenCL = 0,
+  [Default] kOpenGL = 1,
+};
+
+// Indicates the state of setting an effect.
+[Extensible]
+enum SetEffectResult {
+  [Default] kOk = 0,
+  kError = 1,
+};
+
+// Defines which level of blur to apply with the background blur effect.
+[Extensible]
+enum BlurLevel {
+  kLowest,
+  kLight,
+  [Default] kMedium,
+  kHeavy,
+  kMaximum,
+};
+
+// Structure used for configuring and enabling video conferencing effects.
+// This should be kept in sync with the google3 version found in:
+// chromeos/ml/effects_pipeline/effects_config.h
+struct EffectsConfig {
+  // Name of the effect to enable.
+  CameraEffect effect = kNone;
+
+  // How much blur to apply for the background blur effect.
+  BlurLevel blur_level = kMedium;
+
+  // Select which GPU API to use to perform the segmentation inference.
+  GpuApi segmentation_gpu_api = kOpenGL;
+
+  // Maximum number of frames allowed in flight.
+  uint16 graph_max_frames_in_flight = 2;
+};
diff --git a/media/capture/video/chromeos/video_capture_features_chromeos.cc b/media/capture/video/chromeos/video_capture_features_chromeos.cc
index 1375ac5..d579566 100644
--- a/media/capture/video/chromeos/video_capture_features_chromeos.cc
+++ b/media/capture/video/chromeos/video_capture_features_chromeos.cc
@@ -13,7 +13,6 @@
 const char kForceControlFaceAe[] = "force-control-face-ae";
 const char kHdrNetOverride[] = "hdrnet-override";
 const char kAutoFramingOverride[] = "auto-framing-override";
-const char kEffectsOverride[] = "effects-override";
 
 }  // namespace switches
 
diff --git a/media/capture/video/chromeos/video_capture_features_chromeos.h b/media/capture/video/chromeos/video_capture_features_chromeos.h
index 8f36098..d7c2a96 100644
--- a/media/capture/video/chromeos/video_capture_features_chromeos.h
+++ b/media/capture/video/chromeos/video_capture_features_chromeos.h
@@ -22,10 +22,6 @@
 constexpr char kAutoFramingForceEnabled[] = "force-enabled";
 constexpr char kAutoFramingForceDisabled[] = "force-disabled";
 
-CAPTURE_EXPORT extern const char kEffectsOverride[];
-constexpr char kEffectsForceEnabled[] = "force-enabled";
-constexpr char kEffectsForceDisabled[] = "force-disabled";
-
 }  // namespace switches
 
 namespace features {
diff --git a/media/gpu/v4l2/v4l2_video_encode_accelerator.cc b/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
index 1eeac0f..58c78cee 100644
--- a/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
@@ -399,10 +399,10 @@
   // Notify VideoEncoderInfo after initialization.
   VideoEncoderInfo encoder_info;
   encoder_info.implementation_name = "V4L2VideoEncodeAccelerator";
-  encoder_info.has_trusted_rate_controller = true;
-  encoder_info.is_hardware_accelerated = true;
-  encoder_info.supports_native_handle = true;
-  encoder_info.supports_simulcast = false;
+  DCHECK(!encoder_info.has_trusted_rate_controller);
+  DCHECK(encoder_info.is_hardware_accelerated);
+  DCHECK(encoder_info.supports_native_handle);
+  DCHECK(!encoder_info.supports_simulcast);
 
   // V4L2VideoEncodeAccelerator doesn't support either temporal-SVC or
   // spatial-SVC. A single stream shall be output at the desired FPS.
diff --git a/media/gpu/vaapi/vaapi_video_encode_accelerator.cc b/media/gpu/vaapi/vaapi_video_encode_accelerator.cc
index 682f95f..85903cf 100644
--- a/media/gpu/vaapi/vaapi_video_encode_accelerator.cc
+++ b/media/gpu/vaapi/vaapi_video_encode_accelerator.cc
@@ -128,7 +128,7 @@
 
   // The default value of VideoEncoderInfo of VaapiVideoEncodeAccelerator.
   encoder_info_.implementation_name = "VaapiVideoEncodeAccelerator";
-  encoder_info_.has_trusted_rate_controller = true;
+  DCHECK(!encoder_info_.has_trusted_rate_controller);
   DCHECK(encoder_info_.is_hardware_accelerated);
   DCHECK(encoder_info_.supports_native_handle);
   DCHECK(!encoder_info_.supports_simulcast);
diff --git a/media/gpu/vaapi/vaapi_video_encode_accelerator_unittest.cc b/media/gpu/vaapi/vaapi_video_encode_accelerator_unittest.cc
index b7f546b..b45f172 100644
--- a/media/gpu/vaapi/vaapi_video_encode_accelerator_unittest.cc
+++ b/media/gpu/vaapi/vaapi_video_encode_accelerator_unittest.cc
@@ -126,7 +126,7 @@
     }
   }
   return arg.implementation_name == "VaapiVideoEncodeAccelerator" &&
-         arg.supports_native_handle && arg.has_trusted_rate_controller &&
+         arg.supports_native_handle && !arg.has_trusted_rate_controller &&
          arg.is_hardware_accelerated && !arg.supports_simulcast;
 }
 
diff --git a/media/gpu/vaapi/vp8_vaapi_video_encoder_delegate.cc b/media/gpu/vaapi/vp8_vaapi_video_encoder_delegate.cc
index 702ebad..6edd9b0 100644
--- a/media/gpu/vaapi/vp8_vaapi_video_encoder_delegate.cc
+++ b/media/gpu/vaapi/vp8_vaapi_video_encoder_delegate.cc
@@ -32,12 +32,11 @@
 // resolution (180p).
 constexpr uint8_t kMaxQP = 117;
 
-// The upper limitation of the quantization parameter for the software rate
-// controller. This is larger than |kMaxQP| because a driver might ignore the
-// specified maximum quantization parameter when the driver determines the
-// value, but it doesn't ignore the quantization parameter by the software rate
-// controller.
-constexpr uint8_t kMaxQPForSoftwareRateCtrl = 127;
+// WebRTC's default qp values are 15 and 106 for screen sharing, respectively,
+// Set smaller qp values for zero hertz tab sharing, which is triggered when qp
+// values are consecutively less than or equal to 15.
+constexpr uint8_t kScreenMinQP = 8;
+constexpr uint8_t kScreenMaxQP = 106;
 
 // Convert Qindex, whose range is 0-127, to the quantizer parameter used in
 // libvpx vp8 rate control, whose range is 0-63.
@@ -319,7 +318,11 @@
   else
     initial_bitrate_allocation.SetBitrate(0, 0, config.bitrate.target_bps());
 
-  current_params_.max_qp = kMaxQPForSoftwareRateCtrl;
+  if (config.content_type ==
+      VideoEncodeAccelerator::Config::ContentType::kDisplay) {
+    current_params_.min_qp = kScreenMinQP;
+    current_params_.max_qp = kScreenMaxQP;
+  }
 
   // |rate_ctrl_| might be injected for tests.
   if (!rate_ctrl_) {
diff --git a/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc b/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
index cfaca47..fab1ff9 100644
--- a/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
+++ b/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
@@ -237,6 +237,33 @@
   return count;
 }
 
+// Per
+// https://learn.microsoft.com/en-us/windows/win32/medfound/handling-stream-changes,
+// encoders should only accept an input type that matches the currently
+// configured output type. If we want to change the frame rate, a
+// stream restart flow is needed, which in turn generates a key-frame on the
+// stream restart. This is not friendly for WebRTC encoding, which adjusts the
+// encoding frame rate frequently.
+// To mitigate this, we only configure the frame rate during HMFT
+// initialization. On subsequent frame rate update request, if new frame rate is
+// larger than currently configured frame rate and bitrate is kept unchanged,
+// this implies average encoded frame size should decrease proportionally. Since
+// we don't actually configure the new frame rate into HMFT(to avoid stream
+// restart), we emulate this average frame size decrease by proportionally
+// decreasing the target/peak bitrate(which does not require stream restart).
+// This is similar for frame rate update request that is lower than currently
+// configured, by increasing bitrate to emulate average frame size increase.
+// See https://crbug.com/1295815 for more details.
+uint32_t AdjustBitrateToFrameRate(uint32_t bitrate,
+                                  uint32_t configured_framerate,
+                                  uint32_t requested_framerate) {
+  if (requested_framerate == 0u) {
+    return 0u;
+  }
+
+  return bitrate * configured_framerate / requested_framerate;
+}
+
 }  // namespace
 
 class MediaFoundationVideoEncodeAccelerator::EncodeOutput {
@@ -290,8 +317,6 @@
     CHROME_LUID luid)
     : compatible_with_win7_(
           gpu_preferences.enable_media_foundation_vea_on_windows7),
-      disable_dynamic_framerate_update_(
-          gpu_workarounds.disable_dynamic_video_encode_framerate_update),
       frame_rate_(kMaxFrameRateNumerator / kMaxFrameRateDenominator),
       bitrate_(Bitrate::ConstantBitrate(kDefaultTargetBitrate)),
       input_required_(false),
@@ -446,7 +471,7 @@
       std::make_unique<base::WeakPtrFactory<Client>>(client);
   main_client_ = main_client_weak_factory_->GetWeakPtr();
   input_visible_size_ = config.input_visible_size;
-  if (config.initial_framerate.has_value())
+  if (config.initial_framerate.has_value() && config.initial_framerate.value())
     frame_rate_ = config.initial_framerate.value();
   else
     frame_rate_ = kMaxFrameRateNumerator / kMaxFrameRateDenominator;
@@ -544,7 +569,7 @@
 
   VideoEncoderInfo encoder_info;
   encoder_info.implementation_name = "MediaFoundationVideoEncodeAccelerator";
-  encoder_info.has_trusted_rate_controller = true;
+  encoder_info.has_trusted_rate_controller = false;
   DCHECK(encoder_info.is_hardware_accelerated);
   DCHECK(encoder_info.supports_native_handle);
   DCHECK(!encoder_info.supports_simulcast);
@@ -789,11 +814,15 @@
   hr = imf_output_media_type_->SetGUID(MF_MT_SUBTYPE,
                                        VideoCodecToMFSubtype(codec_));
   RETURN_ON_HR_FAILURE(hr, "Couldn't set video format", false);
-  hr = imf_output_media_type_->SetUINT32(MF_MT_AVG_BITRATE,
-                                         bitrate_.target_bps());
+
+  hr = imf_output_media_type_->SetUINT32(
+      MF_MT_AVG_BITRATE, AdjustBitrateToFrameRate(bitrate_.target_bps(),
+                                                  frame_rate_, frame_rate_));
   RETURN_ON_HR_FAILURE(hr, "Couldn't set bitrate", false);
+  configured_frame_rate_ = frame_rate_;
+
   hr = MFSetAttributeRatio(imf_output_media_type_.Get(), MF_MT_FRAME_RATE,
-                           frame_rate_, 1);
+                           configured_frame_rate_, 1);
   RETURN_ON_HR_FAILURE(hr, "Couldn't set frame rate", false);
   hr = MFSetAttributeSize(imf_output_media_type_.Get(), MF_MT_FRAME_SIZE,
                           input_visible_size_.width(),
@@ -823,7 +852,7 @@
   hr = imf_input_media_type_->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_NV12);
   RETURN_ON_HR_FAILURE(hr, "Couldn't set video format", false);
   hr = MFSetAttributeRatio(imf_input_media_type_.Get(), MF_MT_FRAME_RATE,
-                           frame_rate_, 1);
+                           configured_frame_rate_, 1);
   RETURN_ON_HR_FAILURE(hr, "Couldn't set frame rate", false);
   hr = MFSetAttributeSize(imf_input_media_type_.Get(), MF_MT_FRAME_SIZE,
                           input_visible_size_.width(),
@@ -877,14 +906,16 @@
     }
   }
 
-  var.ulVal = bitrate_.target_bps();
+  var.ulVal = AdjustBitrateToFrameRate(bitrate_.target_bps(),
+                                       configured_frame_rate_, frame_rate_);
   hr = codec_api_->SetValue(&CODECAPI_AVEncCommonMeanBitRate, &var);
   if (!compatible_with_win7_) {
     RETURN_ON_HR_FAILURE(hr, "Couldn't set bitrate", false);
   }
 
   if (bitrate_.mode() == Bitrate::Mode::kVariable) {
-    var.ulVal = bitrate_.peak_bps();
+    var.ulVal = AdjustBitrateToFrameRate(bitrate_.peak_bps(),
+                                         configured_frame_rate_, frame_rate_);
     hr = codec_api_->SetValue(&CODECAPI_AVEncCommonMaxBitRate, &var);
     if (!compatible_with_win7_) {
       RETURN_ON_HR_FAILURE(hr, "Couldn't set bitrate", false);
@@ -1454,78 +1485,21 @@
 
   framerate = base::clamp(framerate, 1u, uint32_t{kMaxFrameRateNumerator});
 
-  if (frame_rate_ != framerate) {
-    // When dynamic framerate update is disabled, fallback from current encoder.
-    if (disable_dynamic_framerate_update_) {
-      DLOG(ERROR) << "Dynamic encode framerate update disabled.";
-      NotifyError(kPlatformFailureError);
-    }
-    HRESULT hr = MFSetAttributeRatio(imf_output_media_type_.Get(),
-                                     MF_MT_FRAME_RATE, framerate, 1);
-    RETURN_ON_HR_FAILURE(hr, "Couldn't set frame rate for output type", );
-
-    imf_output_media_type_->SetUINT32(MF_MT_AVG_BITRATE, bitrate.target_bps());
-    RETURN_ON_HR_FAILURE(hr, "Couldn't set average bitrate for output type", );
-
-    hr = MFSetAttributeRatio(imf_input_media_type_.Get(), MF_MT_FRAME_RATE,
-                             framerate, 1);
-    RETURN_ON_HR_FAILURE(hr, "Couldn't set frame rate for input type", );
-
-    // Some HMFTs will reject output type change with MF_E_INVALIDTYPE due
-    // to temporary mismatch between output/input media types, so we always
-    // clear the input/output media types before reconfiguring them
-    // dynamically.
-    hr = encoder_->ProcessMessage(MFT_MESSAGE_COMMAND_DRAIN, 0);
-    RETURN_ON_HR_FAILURE(
-        hr, "Couldn't process message MFT_MESSAGE_COMMAND_DRAIN", );
-
-    DrainPendingOutputs();
-
-    hr = encoder_->ProcessMessage(MFT_MESSAGE_NOTIFY_END_OF_STREAM, 0);
-    RETURN_ON_HR_FAILURE(
-        hr, "Couldn't process message MFT_MESSAGE_NOTIFY_END_OF_STREAM", );
-
-    hr = encoder_->ProcessMessage(MFT_MESSAGE_NOTIFY_END_STREAMING, 0);
-    RETURN_ON_HR_FAILURE(
-        hr, "Couldn't process message MFT_MESSAGE_NOTIFY_END_STREAMING", );
-
-    hr = encoder_->SetInputType(input_stream_id_, nullptr, 0);
-    RETURN_ON_HR_FAILURE(hr, "Couldn't clear input media type.", );
-
-    hr = encoder_->SetOutputType(output_stream_id_, nullptr, 0);
-    RETURN_ON_HR_FAILURE(hr, "Couldn't clear ouput media type.", );
-
-    hr = encoder_->SetOutputType(output_stream_id_,
-                                 imf_output_media_type_.Get(), 0);
-    RETURN_ON_HR_FAILURE(hr, "Couldn't set output media type", );
-
-    hr = encoder_->SetInputType(input_stream_id_, imf_input_media_type_.Get(),
-                                0);
-    RETURN_ON_HR_FAILURE(hr, "Couldn't set input media type", );
-
-    hr = encoder_->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0);
-    RETURN_ON_HR_FAILURE(
-        hr, "Couldn't process message MFT_MESSAGE_NOTIFY_BEGIN_STREAMING", );
-
-    hr = encoder_->ProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0);
-    RETURN_ON_HR_FAILURE(
-        hr, "Couldn't process message MFT_MESSAGE_NOTIFY_START_OF_STREAM", );
-
-    frame_rate_ = framerate;
-  }
-
-  if (bitrate_ != bitrate) {
+  if (bitrate_ != bitrate || frame_rate_ != framerate) {
     bitrate_ = bitrate;
+    frame_rate_ = framerate;
     VARIANT var;
     var.vt = VT_UI4;
-    var.ulVal = bitrate.target_bps();
+    var.ulVal = AdjustBitrateToFrameRate(bitrate.target_bps(),
+                                         configured_frame_rate_, framerate);
     HRESULT hr = codec_api_->SetValue(&CODECAPI_AVEncCommonMeanBitRate, &var);
     if (!compatible_with_win7_) {
       RETURN_ON_HR_FAILURE(hr, "Couldn't update mean bitrate", );
     }
 
     if (bitrate.mode() == Bitrate::Mode::kVariable) {
-      var.ulVal = bitrate.peak_bps();
+      var.ulVal = AdjustBitrateToFrameRate(bitrate.peak_bps(),
+                                           configured_frame_rate_, framerate);
       hr = codec_api_->SetValue(&CODECAPI_AVEncCommonMaxBitRate, &var);
       if (!compatible_with_win7_) {
         RETURN_ON_HR_FAILURE(hr, "Couldn't set max bitrate", );
@@ -1725,22 +1699,4 @@
   return hr;
 }
 
-void MediaFoundationVideoEncodeAccelerator::DrainPendingOutputs() {
-  Microsoft::WRL::ComPtr<IMFMediaEvent> media_event;
-
-  while ((SUCCEEDED(
-      event_generator_->GetEvent(MF_EVENT_FLAG_NO_WAIT, &media_event)))) {
-    MediaEventType event_type;
-    HRESULT hr = media_event->GetType(&event_type);
-    if (FAILED(hr)) {
-      DLOG(ERROR) << "Failed to get the type of media event.";
-      continue;
-    }
-
-    if (event_type == METransformHaveOutput) {
-      ProcessOutput();
-    }
-  }
-}
-
 }  // namespace media
diff --git a/media/gpu/windows/media_foundation_video_encode_accelerator_win.h b/media/gpu/windows/media_foundation_video_encode_accelerator_win.h
index e1eb32c..c95c815e 100644
--- a/media/gpu/windows/media_foundation_video_encode_accelerator_win.h
+++ b/media/gpu/windows/media_foundation_video_encode_accelerator_win.h
@@ -123,9 +123,6 @@
   // Checks for and copies encoded output on |encoder_thread_task_runner_|.
   void ProcessOutput();
 
-  // Drains pending output samples on |encoder_thread_task_runner_|.
-  void DrainPendingOutputs();
-
   // Tries to deliver the input frame to the encoder.
   bool TryToDeliverInputFrame(scoped_refptr<VideoFrame> frame,
                               bool force_keyframe);
@@ -158,7 +155,6 @@
   HRESULT PerformD3DScaling(ID3D11Texture2D* input_texture);
 
   const bool compatible_with_win7_;
-  const bool disable_dynamic_framerate_update_;
 
   // Bitstream buffers ready to be used to return encoded output as a FIFO.
   base::circular_deque<std::unique_ptr<BitstreamBufferRef>>
@@ -177,6 +173,9 @@
   gfx::Size input_visible_size_;
   size_t bitstream_buffer_size_;
   uint32_t frame_rate_;
+  // For recording configured frame rate as we don't dynamically change it.
+  // The default value here will be overridden during initialization.
+  uint32_t configured_frame_rate_ = 30;
   Bitrate bitrate_;
   bool low_latency_mode_;
   int num_temporal_layers_ = 1;
diff --git a/media/midi/midi_manager_android.cc b/media/midi/midi_manager_android.cc
index a51127b..c1c3ed0 100644
--- a/media/midi/midi_manager_android.cc
+++ b/media/midi/midi_manager_android.cc
@@ -4,7 +4,6 @@
 
 #include "media/midi/midi_manager_android.h"
 
-#include "base/android/build_info.h"
 #include "base/bind.h"
 #include "base/feature_list.h"
 #include "base/metrics/field_trial_params.h"
@@ -27,10 +26,6 @@
 namespace {
 
 bool HasSystemFeatureMidi() {
-  // MIDI API was added at Android M.
-  DCHECK_GE(base::android::BuildInfo::GetInstance()->sdk_int(),
-            base::android::SDK_VERSION_MARSHMALLOW);
-
   // Check if the MIDI service actually runs on the system.
   return Java_MidiManagerAndroid_hasSystemFeatureMidi(
       base::android::AttachCurrentThread());
diff --git a/sandbox/linux/services/libc_interceptor.cc b/sandbox/linux/services/libc_interceptor.cc
index e742a90c..3347b15 100644
--- a/sandbox/linux/services/libc_interceptor.cc
+++ b/sandbox/linux/services/libc_interceptor.cc
@@ -6,6 +6,7 @@
 
 #include <dlfcn.h>
 #include <fcntl.h>
+#include <netdb.h>
 #include <pthread.h>
 #include <signal.h>
 #include <stddef.h>
@@ -21,15 +22,81 @@
 #include <string>
 
 #include "base/compiler_specific.h"
+#include "base/debug/dump_without_crashing.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/pickle.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/posix/global_descriptors.h"
 #include "base/posix/unix_domain_socket.h"
+#include "base/sanitizer_buildflags.h"
 #include "base/synchronization/lock.h"
 #include "base/time/time.h"
 
+#if BUILDFLAG(USING_SANITIZER)
+// Sanitizers may override certain libc functions with a weak symbol that points
+// the real symbol to an interceptor symbol. E.g. getaddrinfo ->
+// __interceptor_getaddrinfo. However our own libc overrides below prevent the
+// weak symbol from binding, which leads to errors (especially msan errors) when
+// the sanitizer interception code doesn't run. So we want to call the
+// sanitizer's __interceptor_* version of the symbol if it exists.
+//
+// So here, using a weak symbol we can detect whether a sanitizer has overridden
+// a libc symbol with its own __interceptor_* function. If it's been
+// intercepted, we can call the sanitizer's version instead of the normal
+// RTLD_NEXT version.
+//
+// INTERCEPTOR_DECL declares the weak symbol for the __interceptor_* version and
+// REAL(func) should return the address of the __interceptor_* version of |func|
+// if it exists, otherwise it returns dlsym(RTLD_NEXT, func).
+#define INTERCEPTOR_DECL(ret_type, func, ...) \
+  extern "C" ret_type __interceptor_##func(__VA_ARGS__) __attribute__((weak));
+
+#define REAL(func)                                              \
+  (__interceptor_##func)                                        \
+      ? reinterpret_cast<decltype(&func)>(__interceptor_##func) \
+      : reinterpret_cast<decltype(&func)>(dlsym(RTLD_NEXT, #func))
+
+#else  // BUILDFLAG(USING_SANITIZER)
+
+#define INTERCEPTOR_DECL(...)
+#define REAL(func) reinterpret_cast<decltype(&func)>(dlsym(RTLD_NEXT, #func))
+
+#endif  // BUILDFLAG(USING_SANITIZER)
+
+// When Chrome's interceptors have overridden a libc function but need to call
+// the actual libc version, the following macros take care of calling
+// dlsym(RTLD_NEXT, func), storing the result, handling failures, and disabling
+// CFI checks when calling the resulting pointer. See below for examples.
+#define DLSYM_FUNC_DECL(ret_type, func, ...)    \
+  INTERCEPTOR_DECL(ret_type, func, __VA_ARGS__) \
+                                                \
+  DISABLE_CFI_DLSYM                             \
+  ret_type call_real_##func(__VA_ARGS__)
+
+#define DLSYM_FUNC_BODY(func, dlsym_failed_return_val, ...) \
+  static decltype(&func) fn_ptr = REAL(func);               \
+                                                            \
+  if (!fn_ptr) {                                            \
+    LOG(ERROR) << "Cannot find " #func " with dlsym.";      \
+    return dlsym_failed_return_val;                         \
+  }                                                         \
+                                                            \
+  return fn_ptr(__VA_ARGS__);
+
+// Used to call a |func| that's been declared with DLSYM_FUNC_DECL.
+#define CALL_FUNC(func, ...) call_real_##func(__VA_ARGS__)
+
+// A wrapper that calls libc's getaddrinfo().
+DLSYM_FUNC_DECL(int,
+                getaddrinfo,
+                const char* node,
+                const char* service,
+                const struct addrinfo* hints,
+                struct addrinfo** res) {
+  DLSYM_FUNC_BODY(getaddrinfo, EAI_SYSTEM, node, service, hints, res)
+}
+
 namespace sandbox {
 
 namespace {
@@ -336,4 +403,28 @@
                            InitLibcLocaltimeFunctionsImpl));
 }
 
+namespace {
+std::atomic<bool> g_getaddrinfo_discouraged{false};
+}  // namespace
+
+extern "C" {
+__attribute__((visibility("default"), noinline)) int getaddrinfo(
+    const char* node,
+    const char* service,
+    const struct addrinfo* hints,
+    struct addrinfo** res) {
+  if (g_getaddrinfo_discouraged.load(std::memory_order_relaxed)) {
+    DLOG(FATAL) << "Called getaddrinfo() in a sandboxed process.";
+    base::debug::DumpWithoutCrashing();
+    // In non-debug builds, deliberately fall through to call the real version.
+  }
+
+  return CALL_FUNC(getaddrinfo, node, service, hints, res);
+}
+}
+
+void DiscourageGetaddrinfo() {
+  g_getaddrinfo_discouraged = true;
+}
+
 }  // namespace sandbox
diff --git a/sandbox/linux/services/libc_interceptor.h b/sandbox/linux/services/libc_interceptor.h
index 1089a382..90e2120e 100644
--- a/sandbox/linux/services/libc_interceptor.h
+++ b/sandbox/linux/services/libc_interceptor.h
@@ -16,26 +16,40 @@
 
 // Sandbox interception of libc calls.
 //
-// When we are running in a namespace sandbox certain libc calls will fail
-// (localtime being the motivating example - it needs to read /etc/localtime).
-// We need to intercept these calls and proxy them to a parent process.
-// However, these calls may come from us or from our third_party libraries, so
-// in some cases we can't just change the code.
+// When we are running in a sandbox, sometimes certain libc functions will fail.
+// E.g. getaddrinfo() can fail in all sandboxes as glibc can run arbitrary
+// third-party DNS resolution libraries which we have no hope of sandboxing.
 //
-// It's for these cases that we have the following setup:
+// These libc functions need to be run in a separate process. If they are not
+// called by third party code we can use Chrome's IPC (Mojo) to avoid ever
+// calling these libc functions in a sandboxed process. For example
+// getaddrinfo() is only called by first-party Chrome code and so it can be
+// brokered to an unsandboxed process with regular IPC.
 //
-// We define global functions for those functions which we wish to override.
-// Since we will be first in the dynamic resolution order, the dynamic linker
-// will point callers to our versions of these functions. However, we have the
-// same binary for both the browser and the renderers, which means that our
-// overrides will apply in the browser too.
+// But some of the libc calls are from third party libraries in the sandboxed
+// process and they still must succeed. The motivating example is localtime - it
+// needs to read /etc/localtime and sometimes a variety of locale files. We need
+// to intercept these calls and proxy them to a parent process.
 //
-// Our replacement functions must handle both cases, and either proxy the call
-// to the parent over the IPC back-channel (see
-// https://chromium.googlesource.com/chromium/src/+/main/docs/linux/sandbox_ipc.md)
-// or use dlsym with RTLD_NEXT to resolve the symbol, ignoring any symbols in
-// the current module. Use SetAmZygoteOrRenderer() below to control the mode of
-// operation, which defaults using the dlsym approach.
+// For first-party cases we want to ensure the offending libc function is never
+// called in a sandboxed process, and in third-party cases we want to proxy the
+// call to a parent process. So in both cases we override the libc symbol: we
+// define global functions for those functions which we wish to override. Since
+// our own binary will be first in the dynamic resolution order, the dynamic
+// linker will point callers to our versions of these functions.
+//
+// However, we have the same binary for both the browser and the renderers,
+// which means that our overrides will apply in the browser too. In the browser
+// process, the replacement functions must use dlsym with RTLD_NEXT to resolve
+// the actual libc symbol, ignoring any symbols in the current module. In the
+// sandboxed process, we need to either proxy the call to the parent over the
+// IPC back-channel (see
+// https://chromium.googlesource.com/chromium/src/+/main/docs/linux/sandbox_ipc.md),
+// or if the libc call is not allowed ("first-party case") then we should
+// generate a crash dump and possibly continue with the libc call.
+//
+// Use SetAmZygoteOrRenderer() below to control the proxying of libc calls such
+// as localtime, which defaults using the dlsym approach.
 //
 // Other avenues:
 //
@@ -67,6 +81,13 @@
 // Initializes libc interception. Must be called before sandbox lock down.
 SANDBOX_EXPORT void InitLibcLocaltimeFunctions();
 
+// Any calls to getaddrinfo() will crash in debug builds, or in release/official
+// builds will trigger a crash dump and continue to call the actual
+// getaddrinfo().
+// TODO(mdpenton): change to DisallowGetaddrinfo() once this has been
+// sufficiently tested in the wild.
+SANDBOX_EXPORT void DiscourageGetaddrinfo();
+
 }  // namespace sandbox
 
 #endif  // SANDBOX_LINUX_SERVICES_LIBC_INTERCEPTOR_H_
diff --git a/sandbox/policy/BUILD.gn b/sandbox/policy/BUILD.gn
index ba222e2..fa2ba4d 100644
--- a/sandbox/policy/BUILD.gn
+++ b/sandbox/policy/BUILD.gn
@@ -27,7 +27,6 @@
   ]
   defines = [ "SANDBOX_POLICY_IMPL" ]
   deps = [
-    ":sanitizer_buildflags",
     "//base",
     "//build:chromeos_buildflags",
     "//components/services/screen_ai/buildflags",
@@ -172,11 +171,6 @@
   }
 }
 
-buildflag_header("sanitizer_buildflags") {
-  header = "sanitizer_buildflags.h"
-  flags = [ "USING_SANITIZER=$using_sanitizer" ]
-}
-
 buildflag_header("chromecast_sandbox_allowlist_buildflags") {
   header = "chromecast_sandbox_allowlist_buildflags.h"
   flags = [ "ENABLE_CHROMECAST_GPU_SANDBOX_ALLOWLIST=$is_castos" ]
diff --git a/sandbox/policy/linux/sandbox_linux.cc b/sandbox/policy/linux/sandbox_linux.cc
index 04dec1ae..4cd29571 100644
--- a/sandbox/policy/linux/sandbox_linux.cc
+++ b/sandbox/policy/linux/sandbox_linux.cc
@@ -405,6 +405,13 @@
 
   InitLibcLocaltimeFunctions();
 
+  if (!IsUnsandboxedSandboxType(sandbox_type)) {
+    // No sandboxed process should make use of getaddrinfo() as it is impossible
+    // to sandbox (e.g. glibc loads arbitrary third party DNS resolution
+    // libraries).
+    DiscourageGetaddrinfo();
+  }
+
   // Attempt to limit the future size of the address space of the process.
   // Fine to call with multiple threads as we don't use RLIMIT_STACK.
   int error = 0;
diff --git a/sandbox/policy/linux/sandbox_linux.h b/sandbox/policy/linux/sandbox_linux.h
index 4a55d35b..b921ac9 100644
--- a/sandbox/policy/linux/sandbox_linux.h
+++ b/sandbox/policy/linux/sandbox_linux.h
@@ -12,11 +12,11 @@
 #include "base/check_op.h"
 #include "base/memory/raw_ptr.h"
 #include "base/posix/global_descriptors.h"
+#include "base/sanitizer_buildflags.h"
 #include "sandbox/linux/syscall_broker/broker_command.h"
 #include "sandbox/linux/syscall_broker/broker_file_permission.h"
 #include "sandbox/policy/export.h"
 #include "sandbox/policy/linux/sandbox_seccomp_bpf_linux.h"
-#include "sandbox/policy/sanitizer_buildflags.h"
 
 #if BUILDFLAG(USING_SANITIZER)
 #include <sanitizer/common_interface_defs.h>
diff --git a/services/network/cors/cors_url_loader.cc b/services/network/cors/cors_url_loader.cc
index 09b450b..a6ce8fe 100644
--- a/services/network/cors/cors_url_loader.cc
+++ b/services/network/cors/cors_url_loader.cc
@@ -608,6 +608,14 @@
   timing_allow_failed_flag_ = !PassesTimingAllowOriginCheck(*response_head);
   last_response_url_ = redirect_info.new_url;
 
+  if (!url::Origin::Create(redirect_info.new_url)
+           .IsSameOriginWith(url::Origin::Create(request_.url)) &&
+      base::FeatureList::IsEnabled(features::kPreconnectOnRedirect) &&
+      context_->enable_preconnect()) {
+    context_->PreconnectSockets(1, redirect_info.new_url, true,
+                                isolation_info_.network_anonymization_key());
+  }
+
   if (request_.redirect_mode == mojom::RedirectMode::kManual) {
     CheckTainted(redirect_info);
     deferred_redirect_url_ = std::make_unique<GURL>(redirect_info.new_url);
diff --git a/services/network/public/cpp/features.cc b/services/network/public/cpp/features.cc
index bd761f2..aaa9cc5 100644
--- a/services/network/public/cpp/features.cc
+++ b/services/network/public/cpp/features.cc
@@ -323,4 +323,9 @@
              "PreconnectInNetworkService",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Preconnect to a new origin right when a redirect starts.
+BASE_FEATURE(kPreconnectOnRedirect,
+             "PreconnectOnRedirect",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 }  // namespace network::features
diff --git a/services/network/public/cpp/features.h b/services/network/public/cpp/features.h
index d93f6083..5add76a 100644
--- a/services/network/public/cpp/features.h
+++ b/services/network/public/cpp/features.h
@@ -101,6 +101,8 @@
 
 COMPONENT_EXPORT(NETWORK_CPP) BASE_DECLARE_FEATURE(kPreconnectInNetworkService);
 
+COMPONENT_EXPORT(NETWORK_CPP) BASE_DECLARE_FEATURE(kPreconnectOnRedirect);
+
 }  // namespace features
 }  // namespace network
 
diff --git a/testing/buildbot/chrome.json b/testing/buildbot/chrome.json
index c7a61a0..d67bcac 100644
--- a/testing/buildbot/chrome.json
+++ b/testing/buildbot/chrome.json
@@ -2401,8 +2401,8 @@
           ],
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "ash_crosapi_browsertests",
-        "test_id_prefix": "ninja://chrome/test:ash_crosapi_browsertests/"
+        "test": "ash_crosapi_tests",
+        "test_id_prefix": "ninja://chrome/test:ash_crosapi_tests/"
       },
       {
         "merge": {
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 17c08ca..7186b0a 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -28605,6 +28605,77 @@
       },
       {
         "args": [
+          "--use-persistent-shell",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android24.textpb",
+          "--git-revision=${got_revision}"
+        ],
+        "ci_only": true,
+        "experiment_percentage": 100,
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "chrome_public_persistent_shell_unit_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "chrome_public_persistent_shell_unit_test_apk",
+        "precommit_args": [
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
+        ],
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android25",
+              "path": ".android_emulator/generic_android25"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android25"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 2
+        },
+        "test": "chrome_public_unit_test_apk",
+        "test_id_prefix": "ninja://chrome/android:chrome_public_unit_test_apk/"
+      },
+      {
+        "args": [
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
           "--avd-config=../../tools/android/avd/proto/generic_android24.textpb"
@@ -35425,6 +35496,61 @@
       },
       {
         "args": [
+          "--use-persistent-shell",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--git-revision=${got_revision}"
+        ],
+        "ci_only": true,
+        "experiment_percentage": 100,
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "chrome_public_persistent_shell_unit_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "chrome_public_persistent_shell_unit_test_apk",
+        "precommit_args": [
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
+        ],
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_os": "PQ3A.190801.002",
+              "device_os_flavor": "google",
+              "device_os_type": "userdebug",
+              "device_type": "walleye",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 2
+        },
+        "test": "chrome_public_unit_test_apk",
+        "test_id_prefix": "ninja://chrome/android:chrome_public_unit_test_apk/"
+      },
+      {
+        "args": [
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
         ],
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index e24e81cd..a7d1c0f4 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -1644,8 +1644,8 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "ash_crosapi_browsertests",
-        "test_id_prefix": "ninja://chrome/test:ash_crosapi_browsertests/"
+        "test": "ash_crosapi_tests",
+        "test_id_prefix": "ninja://chrome/test:ash_crosapi_tests/"
       },
       {
         "merge": {
@@ -3237,8 +3237,8 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "ash_crosapi_browsertests",
-        "test_id_prefix": "ninja://chrome/test:ash_crosapi_browsertests/"
+        "test": "ash_crosapi_tests",
+        "test_id_prefix": "ninja://chrome/test:ash_crosapi_tests/"
       },
       {
         "args": [
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 4bbb59b..92a94d66 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -1674,8 +1674,8 @@
           "hard_timeout": 7200,
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "ash_crosapi_browsertests",
-        "test_id_prefix": "ninja://chrome/test:ash_crosapi_browsertests/"
+        "test": "ash_crosapi_tests",
+        "test_id_prefix": "ninja://chrome/test:ash_crosapi_tests/"
       },
       {
         "args": [
@@ -93085,8 +93085,8 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "ash_crosapi_browsertests",
-        "test_id_prefix": "ninja://chrome/test:ash_crosapi_browsertests/"
+        "test": "ash_crosapi_tests",
+        "test_id_prefix": "ninja://chrome/test:ash_crosapi_tests/"
       },
       {
         "isolate_profile_data": true,
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 3c3a15e..dade93e 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -5190,8 +5190,8 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "ash_crosapi_browsertests",
-        "test_id_prefix": "ninja://chrome/test:ash_crosapi_browsertests/"
+        "test": "ash_crosapi_tests",
+        "test_id_prefix": "ninja://chrome/test:ash_crosapi_tests/"
       },
       {
         "args": [
@@ -7054,8 +7054,8 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "ash_crosapi_browsertests",
-        "test_id_prefix": "ninja://chrome/test:ash_crosapi_browsertests/"
+        "test": "ash_crosapi_tests",
+        "test_id_prefix": "ninja://chrome/test:ash_crosapi_tests/"
       },
       {
         "args": [
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index f631fa916..062ea5c0 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -180,8 +180,8 @@
     "label": "//ash/components:ash_components_unittests",
     "type": "windowed_test_launcher",
   },
-  "ash_crosapi_browsertests": {
-    "label": "//chrome/test:ash_crosapi_browsertests",
+  "ash_crosapi_tests": {
+    "label": "//chrome/test:ash_crosapi_tests",
     "type": "windowed_test_launcher",
   },
   "ash_webui_unittests": {
@@ -1678,9 +1678,6 @@
     "type": "additional_compile_target",
   },
   "system_webview_shell_layout_test_apk": {
-    "args": [
-      "--replace-system-package=apks/SystemWebViewShell.apk",
-    ],
     "label": "//android_webview/tools/system_webview_shell:system_webview_shell_layout_test_apk",
     "type": "console_test_launcher",
   },
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 7975d482..d7c0a304 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -459,6 +459,24 @@
       },
     },
 
+    # TODO(crbug/1239300): Remove when persistent_shell experiment is over.
+    'chrome_persistent_shell_tests': {
+       'chrome_public_persistent_shell_unit_test_apk': {
+         'args': [
+           '--use-persistent-shell',
+         ],
+         'ci_only': True,
+         'test': 'chrome_public_unit_test_apk',
+         'experiment_percentage': 100,
+         'swarming': {
+           'shards': 2,
+         },
+         'mixins': [
+           'skia_gold_test',
+         ],
+      }
+    },
+
     'chrome_public_tests': {
       'chrome_public_test_apk': {
         'swarming': {
@@ -3801,7 +3819,7 @@
       # Chrome OS only.
       'ash_components_unittests': {},
       # TODO(crbug.com/1351793) Enable on CQ when stable.
-      'ash_crosapi_browsertests': {
+      'ash_crosapi_tests': {
         'ci_only': True,
       },
       'ash_unittests': {
@@ -5221,6 +5239,7 @@
       'android_smoke_tests',
       'android_specific_chromium_gtests',  # Already includes gl_gtests.
       'android_wpr_record_replay_tests',
+      'chrome_persistent_shell_tests',
       'chromium_gtests',
       'chromium_gtests_for_devices_with_graphical_output',
       'linux_flavor_specific_chromium_gtests',
@@ -5300,6 +5319,7 @@
     #   'android_specific_chromium_gtests',  # Already includes gl_gtests.
     #   'chromium_gtests',
     #   'chromium_gtests_for_devices_with_graphical_output',
+      'chrome_persistent_shell_tests',
       'chrome_public_tests',
     #   'linux_flavor_specific_chromium_gtests',
       'system_webview_shell_instrumentation_tests',
diff --git a/testing/merge_scripts/code_coverage/merge_js_lib.py b/testing/merge_scripts/code_coverage/merge_js_lib.py
index a9cf1ae9..2099452 100644
--- a/testing/merge_scripts/code_coverage/merge_js_lib.py
+++ b/testing/merge_scripts/code_coverage/merge_js_lib.py
@@ -320,7 +320,10 @@
                          file_path)
             continue
 
-        if len(script_data['sourceMapURL']) == 0:
+        # TODO(crbug/1373753): For now we exclude any sourcemaps that are 0
+        # length and also that don't begin with a data URL designation.
+        if len(script_data['sourceMapURL']) == 0 or not script_data[
+                'sourceMapURL'].startswith(_SOURCEMAPPING_DATA_URL_PREFIX):
             continue
 
         decoded_sourcemap = base64.b64decode(
diff --git a/testing/merge_scripts/code_coverage/merge_js_lib_test.py b/testing/merge_scripts/code_coverage/merge_js_lib_test.py
index 4c83151..1d4e2bc3 100755
--- a/testing/merge_scripts/code_coverage/merge_js_lib_test.py
+++ b/testing/merge_scripts/code_coverage/merge_js_lib_test.py
@@ -534,6 +534,37 @@
         finally:
             shutil.rmtree(scripts_dir)
 
+    def test_non_data_urls_are_ignored(self):
+        test_script_file = """{
+"text": "test\\ncontents",
+"url": "http://test_url",
+"sourceMapURL":"%s"
+}"""
+
+        scripts_dir = None
+        expected_files = []
+
+        try:
+            scripts_dir = tempfile.mkdtemp()
+            file_path = os.path.join(scripts_dir, 'external_map.js.json')
+            expected_files = [file_path]
+
+            # Write a script with an external URL as the sourcemap, this should
+            # exclude it from being written to disk.
+            with open(file_path, 'w') as f:
+                f.write(test_script_file % 'external.map')
+
+            merger.write_parsed_scripts(scripts_dir, source_dir='')
+            actual_files = []
+
+            for root, _, files in os.walk(scripts_dir):
+                for file_name in files:
+                    actual_files.append(os.path.join(root, file_name))
+
+            self.assertCountEqual(expected_files, actual_files)
+        finally:
+            shutil.rmtree(scripts_dir)
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index f6475c64..bf51235 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -7874,6 +7874,25 @@
             ]
         }
     ],
+    "PageInfoAboutThisSiteDescriptionPlaceholder": [
+        {
+            "platforms": [
+                "android",
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "PageInfoAboutThisSiteDescriptionPlaceholder"
+                    ]
+                }
+            ]
+        }
+    ],
     "PageInfoAboutThisSiteMoreInfo": [
         {
             "platforms": [
@@ -8104,7 +8123,7 @@
             ],
             "experiments": [
                 {
-                    "name": "enabled3_doublekey",
+                    "name": "enabled_doublekey",
                     "enable_features": [
                         "EnableDoubleKeyNetworkAnonymizationKey",
                         "ForceIsolationInfoFrameOriginToTopLevelFrame",
@@ -8118,7 +8137,7 @@
                     ]
                 },
                 {
-                    "name": "enabled3_triplekey",
+                    "name": "enabled_triplekey",
                     "enable_features": [
                         "PartitionConnectionsByNetworkIsolationKey",
                         "PartitionDomainReliabilityByNetworkIsolationKey",
@@ -8128,6 +8147,32 @@
                         "PartitionSSLSessionsByNetworkIsolationKey",
                         "SplitHostCacheByNetworkIsolationKey"
                     ]
+                },
+                {
+                    "name": "enabled_triple_double_key",
+                    "enable_features": [
+                        "EnableDoubleKeyNetworkAnonymizationKey",
+                        "PartitionConnectionsByNetworkIsolationKey",
+                        "PartitionDomainReliabilityByNetworkIsolationKey",
+                        "PartitionExpectCTStateByNetworkIsolationKey",
+                        "PartitionHttpServerPropertiesByNetworkIsolationKey",
+                        "PartitionNelAndReportingByNetworkIsolationKey",
+                        "PartitionSSLSessionsByNetworkIsolationKey",
+                        "SplitHostCacheByNetworkIsolationKey"
+                    ]
+                },
+                {
+                    "name": "enabled_triple_double_cross_site_key",
+                    "enable_features": [
+                        "PartitionConnectionsByNetworkIsolationKey",
+                        "PartitionDomainReliabilityByNetworkIsolationKey",
+                        "PartitionExpectCTStateByNetworkIsolationKey",
+                        "PartitionHttpServerPropertiesByNetworkIsolationKey",
+                        "PartitionNelAndReportingByNetworkIsolationKey",
+                        "PartitionSSLSessionsByNetworkIsolationKey",
+                        "SplitHostCacheByNetworkIsolationKey",
+                        "kEnableCrossSiteFlagNetworkAnonymizationKey"
+                    ]
                 }
             ]
         }
@@ -9401,6 +9446,25 @@
             ]
         }
     ],
+    "SafeBrowsingSevenZipEvaluationEnabled": [
+        {
+            "platforms": [
+                "chromeos",
+                "chromeos_lacros",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "SafeBrowsingSevenZipEvaluationEnabled"
+                    ]
+                }
+            ]
+        }
+    ],
     "ScrollUnification": [
         {
             "platforms": [
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index 1f6aab38..efb2ee4 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -169,6 +169,7 @@
     "platform/web_audio_bus.h",
     "platform/web_audio_device.h",
     "platform/web_audio_latency_hint.h",
+    "platform/web_audio_sink_descriptor.h",
     "platform/web_audio_source_provider.h",
     "platform/web_back_forward_cache_loader_helper.h",
     "platform/web_blob_info.h",
diff --git a/third_party/blink/public/mojom/file_system_access/file_system_access_manager.mojom b/third_party/blink/public/mojom/file_system_access/file_system_access_manager.mojom
index 6ff8f34..c6056d4 100644
--- a/third_party/blink/public/mojom/file_system_access/file_system_access_manager.mojom
+++ b/third_party/blink/public/mojom/file_system_access/file_system_access_manager.mojom
@@ -122,7 +122,14 @@
   // Token redemption can fail if the id of the process trying to redeem the
   // token does not match the id assigned to the token at creation or if the
   // FileSystemAccessManager does not have record of the token.
+  // May show a prompt to the user if the entry corresponds to a sensitive path.
+  // getAsFileSystemHandle() is an async API that can only be called
+  // synchronously while handling the drop event (i.e. as a direct result of
+  // some user interaction, and at the time of the interaction).
+  // Returns an error code if something failed, or a valid entry on success.
+  // TODO(https://crbug.com/1327821): Replace this with expected<T, E> if/when
+  // it becomes available for mojom.
   GetEntryFromDataTransferToken(
     pending_remote<FileSystemAccessDataTransferToken> token
-  )  => (FileSystemAccessEntry entry);
+  )  => (FileSystemAccessError result, FileSystemAccessEntry? entry);
 };
diff --git a/third_party/blink/public/platform/platform.h b/third_party/blink/public/platform/platform.h
index 4bbd5c4..bb829520 100644
--- a/third_party/blink/public/platform/platform.h
+++ b/third_party/blink/public/platform/platform.h
@@ -125,6 +125,7 @@
 class UserMetricsAction;
 class WebAudioBus;
 class WebAudioLatencyHint;
+class WebAudioSinkDescriptor;
 class WebCrypto;
 class WebDedicatedWorker;
 class WebDedicatedWorkerHostFactoryClient;
@@ -209,6 +210,7 @@
 
   // Creates an audio output device platform interface for Web Audio API.
   virtual std::unique_ptr<WebAudioDevice> CreateAudioDevice(
+      const WebAudioSinkDescriptor& sink_descriptor,
       unsigned number_of_output_channels,
       const WebAudioLatencyHint& latency_hint,
       WebAudioDevice::RenderCallback*) {
diff --git a/third_party/blink/public/platform/web_audio_sink_descriptor.h b/third_party/blink/public/platform/web_audio_sink_descriptor.h
new file mode 100644
index 0000000..1a7de62
--- /dev/null
+++ b/third_party/blink/public/platform/web_audio_sink_descriptor.h
@@ -0,0 +1,49 @@
+// 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 THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_AUDIO_SINK_DESCRIPTOR_H_
+#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_AUDIO_SINK_DESCRIPTOR_H_
+
+#include "base/check_op.h"
+#include "base/notreached.h"
+#include "third_party/blink/public/platform/web_string.h"
+
+namespace blink {
+
+// This descriptor object must be created after proper validation of |sink_id|
+// in AudioContext. This object is created by AudioContext in blink, and
+// consumed by RendererWebAudioDeviceImpl in media. Note that this class does
+// NOT do the vailidation of an identifier.
+class WebAudioSinkDescriptor {
+ public:
+  enum AudioSinkType {
+    // A sink type that produces actual sound via a physical audio device.
+    kAudible,
+    // A sink type that is driven by a fake audio device. (e.g. worker thread)
+    kSilent,
+    kLastValue
+  };
+
+  // For an "audible" sink with a user-selected identifier. The empty string
+  // on |sink_id| means the system's default audio device.
+  explicit WebAudioSinkDescriptor(const WebString& sink_id)
+      : type_(kAudible), sink_id_(sink_id) {}
+
+  // For a "silent" sink.
+  explicit WebAudioSinkDescriptor() : type_(kSilent) {}
+
+  AudioSinkType Type() const { return type_; }
+  WebString SinkId() const {
+    DCHECK_EQ(type_, kAudible);
+    return sink_id_;
+  }
+
+ private:
+  AudioSinkType type_;
+  WebString sink_id_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_AUDIO_SINK_DESCRIPTOR_H_
diff --git a/third_party/blink/renderer/controller/blink_initializer.cc b/third_party/blink/renderer/controller/blink_initializer.cc
index c9803571..46d753a 100644
--- a/third_party/blink/renderer/controller/blink_initializer.cc
+++ b/third_party/blink/renderer/controller/blink_initializer.cc
@@ -56,7 +56,6 @@
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/html/parser/atomic_html_token.h"
 #include "third_party/blink/renderer/core/html/parser/literal_buffer.h"
-#include "third_party/blink/renderer/platform/bindings/microtask.h"
 #include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
 #include "third_party/blink/renderer/platform/disk_data_allocator.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
diff --git a/third_party/blink/renderer/core/animation/animation_test.cc b/third_party/blink/renderer/core/animation/animation_test.cc
index 2504043..45da6bf5 100644
--- a/third_party/blink/renderer/core/animation/animation_test.cc
+++ b/third_party/blink/renderer/core/animation/animation_test.cc
@@ -66,7 +66,6 @@
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
 #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
 #include "third_party/blink/renderer/platform/animation/compositor_animation.h"
-#include "third_party/blink/renderer/platform/bindings/microtask.h"
 #include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/thread_state.h"
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.cc b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
index 3b2ac4eb..7a4079c 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
@@ -32,7 +32,6 @@
 #include "third_party/blink/renderer/core/page/page_animator.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/pre_paint_tree_walk.h"
-#include "third_party/blink/renderer/platform/bindings/microtask.h"
 #include "third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index a3904e5..0b4458b 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -317,7 +317,6 @@
 #include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
 #include "third_party/blink/renderer/platform/bindings/exception_messages.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/blink/renderer/platform/bindings/microtask.h"
 #include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
 #include "third_party/blink/renderer/platform/bindings/source_location.h"
 #include "third_party/blink/renderer/platform/bindings/v8_dom_wrapper.h"
diff --git a/third_party/blink/renderer/core/dom/node.cc b/third_party/blink/renderer/core/dom/node.cc
index cec6794..1e59698 100644
--- a/third_party/blink/renderer/core/dom/node.cc
+++ b/third_party/blink/renderer/core/dom/node.cc
@@ -127,7 +127,6 @@
 #include "third_party/blink/renderer/core/trustedtypes/trusted_script.h"
 #include "third_party/blink/renderer/platform/bindings/dom_data_store.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/blink/renderer/platform/bindings/microtask.h"
 #include "third_party/blink/renderer/platform/bindings/v8_dom_wrapper.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/instrumentation/instance_counters.h"
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index 3ef152f..33cd38a 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -1997,6 +1997,7 @@
 
 void WebViewImpl::DidAttachLocalMainFrame() {
   DCHECK(MainFrameImpl());
+  DCHECK(!remote_main_frame_host_remote_);
 
   LocalFrame* local_frame = MainFrameImpl()->GetFrame();
   local_frame->WasAttachedAsLocalMainFrame();
@@ -2045,6 +2046,7 @@
   DCHECK(main_frame_host);
   DCHECK(main_frame);
   DCHECK(!MainFrameImpl());
+  DCHECK(!local_main_frame_host_remote_);
 
   RemoteFrame* remote_frame = DynamicTo<RemoteFrame>(GetPage()->MainFrame());
   remote_frame->WasAttachedAsRemoteMainFrame(std::move(main_frame));
diff --git a/third_party/blink/renderer/core/frame/local_frame_back_forward_cache_test.cc b/third_party/blink/renderer/core/frame/local_frame_back_forward_cache_test.cc
index 4a492ad..19c19c9 100644
--- a/third_party/blink/renderer/core/frame/local_frame_back_forward_cache_test.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_back_forward_cache_test.cc
@@ -18,7 +18,6 @@
 #include "third_party/blink/renderer/core/script/classic_script.h"
 #include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
 #include "third_party/blink/renderer/core/testing/fake_local_frame_host.h"
-#include "third_party/blink/renderer/platform/bindings/microtask.h"
 #include "third_party/blink/renderer/platform/scheduler/public/event_loop.h"
 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
 
diff --git a/third_party/blink/renderer/core/frame/web_frame_test.cc b/third_party/blink/renderer/core/frame/web_frame_test.cc
index 1dc352b5..45b323b5 100644
--- a/third_party/blink/renderer/core/frame/web_frame_test.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_test.cc
@@ -187,7 +187,6 @@
 #include "third_party/blink/renderer/core/testing/scoped_fake_plugin_registry.h"
 #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/bindings/microtask.h"
 #include "third_party/blink/renderer/platform/blob/testing/fake_blob.h"
 #include "third_party/blink/renderer/platform/exported/wrapped_resource_request.h"
 #include "third_party/blink/renderer/platform/keyboard_codes.h"
diff --git a/third_party/blink/renderer/core/html/html_slot_element.cc b/third_party/blink/renderer/core/html/html_slot_element.cc
index b1507fb6..98eb0ed 100644
--- a/third_party/blink/renderer/core/html/html_slot_element.cc
+++ b/third_party/blink/renderer/core/html/html_slot_element.cc
@@ -47,7 +47,6 @@
 #include "third_party/blink/renderer/core/html_names.h"
 #include "third_party/blink/renderer/core/probe/core_probes.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
-#include "third_party/blink/renderer/platform/bindings/microtask.h"
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.cc b/third_party/blink/renderer/core/html/media/html_media_element.cc
index 67bc27b3..87f4fa20 100644
--- a/third_party/blink/renderer/core/html/media/html_media_element.cc
+++ b/third_party/blink/renderer/core/html/media/html_media_element.cc
@@ -732,8 +732,8 @@
     }
   } else if (name == html_names::kLatencyhintAttr &&
              RuntimeEnabledFeatures::MediaLatencyHintEnabled()) {
-    if (GetWebMediaPlayer())
-      GetWebMediaPlayer()->SetLatencyHint(latencyHint());
+    if (web_media_player_)
+      web_media_player_->SetLatencyHint(latencyHint());
   } else {
     HTMLElement::ParseAttribute(params);
   }
@@ -1164,8 +1164,8 @@
     // to deal with this properly. https://crbug.com/789737
     load_state_ = kWaitingForSource;
     SetShouldDelayLoadEvent(false);
-    if (!GetWebMediaPlayer() || (ready_state_ < kHaveFutureData &&
-                                 ready_state_maximum_ < kHaveFutureData)) {
+    if (!web_media_player_ || (ready_state_ < kHaveFutureData &&
+                               ready_state_maximum_ < kHaveFutureData)) {
       SetNetworkState(kNetworkEmpty);
     } else {
       UseCounter::Count(GetDocument(),
@@ -1392,7 +1392,7 @@
   bool can_load_resource =
       source.IsMediaStream() || CanLoadURL(url, content_type);
   if (attempt_load && can_load_resource) {
-    DCHECK(!GetWebMediaPlayer());
+    DCHECK(!web_media_player_);
 
     // Conditionally defer the load if effective preload is 'none'.
     // Skip this optional deferral for MediaStream sources or any blob URL,
@@ -1614,8 +1614,7 @@
 }
 
 bool HTMLMediaElement::PausedWhenVisible() const {
-  return paused_ && GetWebMediaPlayer() &&
-         !GetWebMediaPlayer()->PausedWhenHidden();
+  return paused_ && web_media_player_ && !web_media_player_->PausedWhenHidden();
 }
 
 void HTMLMediaElement::DidAudioOutputSinkChanged(
@@ -1647,11 +1646,11 @@
 }
 
 void HTMLMediaElement::TextTrackReadyStateChanged(TextTrack* track) {
-  if (GetWebMediaPlayer() &&
+  if (web_media_player_ &&
       text_tracks_when_resource_selection_began_.Contains(track)) {
     if (track->GetReadinessState() != TextTrack::kLoading) {
       SetReadyState(
-          static_cast<ReadyState>(GetWebMediaPlayer()->GetReadyState()));
+          static_cast<ReadyState>(web_media_player_->GetReadyState()));
     }
   } else {
     // The track readiness state might have changed as a result of the user
@@ -1723,14 +1722,14 @@
 }
 
 bool HTMLMediaElement::IsMediaDataCorsSameOrigin() const {
-  if (!GetWebMediaPlayer())
+  if (!web_media_player_)
     return true;
 
-  const auto network_state = GetWebMediaPlayer()->GetNetworkState();
+  const auto network_state = web_media_player_->GetNetworkState();
   if (network_state == WebMediaPlayer::kNetworkStateNetworkError)
     return false;
 
-  return !GetWebMediaPlayer()->WouldTaintOrigin();
+  return !web_media_player_->WouldTaintOrigin();
 }
 
 void HTMLMediaElement::StartProgressEventTimer() {
@@ -1844,7 +1843,7 @@
 }
 
 void HTMLMediaElement::NetworkStateChanged() {
-  SetNetworkState(GetWebMediaPlayer()->GetNetworkState());
+  SetNetworkState(web_media_player_->GetNetworkState());
 }
 
 void HTMLMediaElement::MediaLoadingFailed(WebMediaPlayer::NetworkState error,
@@ -1966,7 +1965,7 @@
   if (!MediaShouldBeOpaque()) {
     // Schedule one last progress event so we guarantee that at least one is
     // fired for files that load very quickly.
-    if (GetWebMediaPlayer() && GetWebMediaPlayer()->DidLoadingProgress())
+    if (web_media_player_ && web_media_player_->DidLoadingProgress())
       ScheduleEvent(event_type_names::kProgress);
     ScheduleEvent(event_type_names::kSuspend);
     SetNetworkState(kNetworkIdle);
@@ -1978,7 +1977,7 @@
 }
 
 void HTMLMediaElement::ReadyStateChanged() {
-  SetReadyState(static_cast<ReadyState>(GetWebMediaPlayer()->GetReadyState()));
+  SetReadyState(static_cast<ReadyState>(web_media_player_->GetReadyState()));
 }
 
 void HTMLMediaElement::SetReadyState(ReadyState state) {
@@ -2218,7 +2217,7 @@
 
   DCHECK(previous_progress_time_);
 
-  if (GetWebMediaPlayer() && GetWebMediaPlayer()->DidLoadingProgress()) {
+  if (web_media_player_ && web_media_player_->DidLoadingProgress()) {
     ScheduleEvent(event_type_names::kProgress);
     previous_progress_time_ = base::ElapsedTimer();
     sent_stalled_event_ = false;
@@ -2357,7 +2356,7 @@
   // we will ask the media engine to "seek" to the current movie time, which may
   // be a noop and not generate a timechanged callback. This means seeking_
   // will never be cleared and we will never fire a 'seeked' event.
-  double media_time = GetWebMediaPlayer()->MediaTimeForTimeValue(time);
+  double media_time = web_media_player_->MediaTimeForTimeValue(time);
   if (time != media_time) {
     DVLOG(3) << "seek(" << *this << ", " << time
              << ") - media timeline equivalent is " << media_time;
@@ -2387,8 +2386,8 @@
   ScheduleEvent(event_type_names::kSeeking);
 
   // 11 - Set the current playback position to the given new playback position.
-  GetWebMediaPlayer()->Seek(time);
-  GetWebMediaPlayer()->OnTimeUpdate();
+  web_media_player_->Seek(time);
+  web_media_player_->OnTimeUpdate();
 
   // 14-17 are handled, if necessary, when the engine signals a readystate
   // change or otherwise satisfies seek completion and signals a time change.
@@ -2419,11 +2418,11 @@
 }
 
 bool HTMLMediaElement::HasVideo() const {
-  return GetWebMediaPlayer() && GetWebMediaPlayer()->HasVideo();
+  return web_media_player_ && web_media_player_->HasVideo();
 }
 
 bool HTMLMediaElement::HasAudio() const {
-  return GetWebMediaPlayer() && GetWebMediaPlayer()->HasAudio();
+  return web_media_player_ && web_media_player_->HasAudio();
 }
 
 bool HTMLMediaElement::seeking() const {
@@ -2451,8 +2450,8 @@
   if (ready_state_ == kHaveNothing)
     return 0;
 
-  if (GetWebMediaPlayer())
-    return GetWebMediaPlayer()->CurrentTime();
+  if (web_media_player_)
+    return web_media_player_->CurrentTime();
 
   if (ready_state_ >= kHaveMetadata) {
     DVLOG(3) << __func__ << " readyState = " << ready_state_
@@ -2855,8 +2854,8 @@
 void HTMLMediaElement::setPreservesPitch(bool preserves_pitch) {
   preserves_pitch_ = preserves_pitch;
 
-  if (GetWebMediaPlayer())
-    GetWebMediaPlayer()->SetPreservesPitch(preserves_pitch_);
+  if (web_media_player_)
+    web_media_player_->SetPreservesPitch(preserves_pitch_);
 }
 
 double HTMLMediaElement::latencyHint() const {
@@ -2875,13 +2874,13 @@
 }
 
 void HTMLMediaElement::FlingingStarted() {
-  if (GetWebMediaPlayer())
-    GetWebMediaPlayer()->FlingingStarted();
+  if (web_media_player_)
+    web_media_player_->FlingingStarted();
 }
 
 void HTMLMediaElement::FlingingStopped() {
-  if (GetWebMediaPlayer())
-    GetWebMediaPlayer()->FlingingStopped();
+  if (web_media_player_)
+    web_media_player_->FlingingStopped();
 }
 
 void HTMLMediaElement::CloseMediaSource() {
@@ -3003,8 +3002,8 @@
   if (EffectiveMediaVolume() && PotentiallyPlaying())
     was_always_muted_ = false;
 
-  if (GetWebMediaPlayer())
-    GetWebMediaPlayer()->SetVolume(EffectiveMediaVolume());
+  if (web_media_player_)
+    web_media_player_->SetVolume(EffectiveMediaVolume());
 
   autoplay_policy_->StopAutoplayMutedWhenVisible();
 }
@@ -3035,8 +3034,8 @@
 
   // This is called at the end to make sure the WebMediaPlayer has the right
   // information.
-  if (GetWebMediaPlayer())
-    GetWebMediaPlayer()->SetVolume(EffectiveMediaVolume());
+  if (web_media_player_)
+    web_media_player_->SetVolume(EffectiveMediaVolume());
 
   autoplay_policy_->StopAutoplayMutedWhenVisible();
 }
@@ -3150,7 +3149,7 @@
       enabled_track_ids.push_back(track->id());
   }
 
-  GetWebMediaPlayer()->EnabledAudioTracksChanged(enabled_track_ids);
+  web_media_player_->EnabledAudioTracksChanged(enabled_track_ids);
 }
 
 WebMediaPlayer::TrackId HTMLMediaElement::AddAudioTrack(
@@ -3194,8 +3193,8 @@
     media_source_attachment_->OnTrackChanged(media_source_tracer_, track);
 
   WebMediaPlayer::TrackId id = track->id();
-  GetWebMediaPlayer()->SelectedVideoTrackChanged(track->selected() ? &id
-                                                                   : nullptr);
+  web_media_player_->SelectedVideoTrackChanged(track->selected() ? &id
+                                                                 : nullptr);
 }
 
 WebMediaPlayer::TrackId HTMLMediaElement::AddVideoTrack(
@@ -3634,7 +3633,7 @@
   // 4.8.12.9 steps 12-14. Needed if no ReadyState change is associated with the
   // seek.
   if (seeking_ && ready_state_ >= kHaveCurrentData &&
-      !GetWebMediaPlayer()->Seeking()) {
+      !web_media_player_->Seeking()) {
     FinishSeek();
   }
 
@@ -3755,10 +3754,10 @@
   if (media_source_attachment_)
     return media_source_attachment_->BufferedInternal(media_source_tracer_);
 
-  if (!GetWebMediaPlayer())
+  if (!web_media_player_)
     return {};
 
-  return GetWebMediaPlayer()->Buffered();
+  return web_media_player_->Buffered();
 }
 
 TimeRanges* HTMLMediaElement::buffered() const {
@@ -3779,13 +3778,13 @@
 }
 
 WebTimeRanges HTMLMediaElement::SeekableInternal() const {
-  if (!GetWebMediaPlayer())
+  if (!web_media_player_)
     return {};
 
   if (media_source_attachment_)
     return media_source_attachment_->SeekableInternal(media_source_tracer_);
 
-  return GetWebMediaPlayer()->Seekable();
+  return web_media_player_->Seekable();
 }
 
 TimeRanges* HTMLMediaElement::seekable() const {
@@ -3817,8 +3816,8 @@
     return false;
 
   DCHECK_EQ(GetDirectionOfPlayback(), kForward);
-  if (auto* wmp = GetWebMediaPlayer()) {
-    return wmp->IsEnded() &&
+  if (web_media_player_) {
+    return web_media_player_->IsEnded() &&
            (loop_condition == LoopCondition::kIgnored || !Loop() ||
             dur <= std::numeric_limits<double>::epsilon());
   }
@@ -3837,7 +3836,7 @@
 }
 
 void HTMLMediaElement::UpdatePlayState(bool pause_speech /* = true */) {
-  bool is_playing = GetWebMediaPlayer() && !GetWebMediaPlayer()->Paused();
+  bool is_playing = web_media_player_ && !web_media_player_->Paused();
   bool should_be_playing = PotentiallyPlaying();
 
   DVLOG(3) << "updatePlayState(" << *this
@@ -3852,9 +3851,9 @@
       // Set rate, muted before calling play in case they were set before the
       // media engine was setup.  The media engine should just stash the rate
       // and muted values since it isn't already playing.
-      GetWebMediaPlayer()->SetRate(playbackRate());
-      GetWebMediaPlayer()->SetVolume(EffectiveMediaVolume());
-      GetWebMediaPlayer()->Play();
+      web_media_player_->SetRate(playbackRate());
+      web_media_player_->SetVolume(EffectiveMediaVolume());
+      web_media_player_->Play();
       if (::features::IsTextBasedAudioDescriptionEnabled())
         SpeechSynthesis()->Resume();
 
@@ -3871,7 +3870,7 @@
     playing_ = true;
   } else {  // Should not be playing right now
     if (is_playing) {
-      GetWebMediaPlayer()->Pause();
+      web_media_player_->Pause();
 
       if (pause_speech && ::features::IsTextBasedAudioDescriptionEnabled())
         SpeechSynthesis()->Pause();
@@ -3949,13 +3948,13 @@
   if (state == mojom::FrameLifecycleState::kFrozenAutoResumeMedia && playing_) {
     paused_by_context_paused_ = true;
     pause();
-    if (auto* web_player = GetWebMediaPlayer()) {
-      web_player->OnFrozen();
+    if (web_media_player_) {
+      web_media_player_->OnFrozen();
     }
   } else if (state == mojom::FrameLifecycleState::kFrozen && playing_) {
     pause();
-    if (auto* web_player = GetWebMediaPlayer()) {
-      web_player->OnFrozen();
+    if (web_media_player_) {
+      web_media_player_->OnFrozen();
     }
   } else if (state == mojom::FrameLifecycleState::kRunning &&
              paused_by_context_paused_) {
@@ -4020,11 +4019,11 @@
   // We use the WebMediaPlayer's network state instead of |network_state_| since
   // it's value is unreliable prior to ready state kHaveMetadata.
   if (!media_source_attachment_) {
-    const auto* wmp = GetWebMediaPlayer();
-    if (!wmp) {
+    if (!web_media_player_) {
       if (network_state_ == kNetworkLoading)
         return true;
-    } else if (wmp->GetNetworkState() == WebMediaPlayer::kNetworkStateLoading) {
+    } else if (web_media_player_->GetNetworkState() ==
+               WebMediaPlayer::kNetworkStateLoading) {
       return true;
     }
   }
@@ -4216,15 +4215,15 @@
 }
 
 uint64_t HTMLMediaElement::webkitAudioDecodedByteCount() const {
-  if (!GetWebMediaPlayer())
+  if (!web_media_player_)
     return 0;
-  return GetWebMediaPlayer()->AudioDecodedByteCount();
+  return web_media_player_->AudioDecodedByteCount();
 }
 
 uint64_t HTMLMediaElement::webkitVideoDecodedByteCount() const {
-  if (!GetWebMediaPlayer())
+  if (!web_media_player_)
     return 0;
-  return GetWebMediaPlayer()->VideoDecodedByteCount();
+  return web_media_player_->VideoDecodedByteCount();
 }
 
 bool HTMLMediaElement::IsURLAttribute(const Attribute& attribute) const {
diff --git a/third_party/blink/renderer/core/html/media/html_media_element_test.cc b/third_party/blink/renderer/core/html/media/html_media_element_test.cc
index 0445fbf4..9617b250 100644
--- a/third_party/blink/renderer/core/html/media/html_media_element_test.cc
+++ b/third_party/blink/renderer/core/html/media/html_media_element_test.cc
@@ -334,6 +334,14 @@
     Media()->SetNetworkState(state);
   }
 
+  bool MediaIsPlaying() const { return Media()->playing_; }
+
+  void ResetWebMediaPlayer() const { Media()->web_media_player_.reset(); }
+
+  void MediaContextLifecycleStateChanged(mojom::FrameLifecycleState state) {
+    Media()->ContextLifecycleStateChanged(state);
+  }
+
   bool MediaShouldBeOpaque() const { return Media()->MediaShouldBeOpaque(); }
 
   void SetError(MediaError* err) { Media()->MediaEngineError(err); }
@@ -1417,4 +1425,46 @@
   Media()->Play();
 }
 
+TEST_P(HTMLMediaElementTest, CanFreezeWithoutMediaPlayerAttached) {
+  Media()->SetSrc(SrcSchemeToURL(TestURLScheme::kHttp));
+  test::RunPendingTasks();
+
+  SetReadyState(HTMLMediaElement::kHaveEnoughData);
+  test::RunPendingTasks();
+
+  EXPECT_CALL(*MockMediaPlayer(), SetWasPlayedWithUserActivation(false));
+  Media()->Play();
+
+  ResetWebMediaPlayer();
+  EXPECT_FALSE(Media()->GetWebMediaPlayer());
+  EXPECT_TRUE(MediaIsPlaying());
+
+  // Freeze with auto resume.
+  MediaContextLifecycleStateChanged(
+      mojom::FrameLifecycleState::kFrozenAutoResumeMedia);
+
+  EXPECT_FALSE(MediaIsPlaying());
+}
+
+TEST_P(HTMLMediaElementTest, CanFreezeWithMediaPlayerAttached) {
+  Media()->SetSrc(SrcSchemeToURL(TestURLScheme::kHttp));
+  test::RunPendingTasks();
+
+  SetReadyState(HTMLMediaElement::kHaveEnoughData);
+  test::RunPendingTasks();
+
+  EXPECT_CALL(*MockMediaPlayer(), SetWasPlayedWithUserActivation(false));
+  EXPECT_CALL(*MockMediaPlayer(), OnFrozen());
+  Media()->Play();
+
+  EXPECT_TRUE(Media()->GetWebMediaPlayer());
+  EXPECT_TRUE(MediaIsPlaying());
+
+  // Freeze with auto resume.
+  MediaContextLifecycleStateChanged(
+      mojom::FrameLifecycleState::kFrozenAutoResumeMedia);
+
+  EXPECT_FALSE(MediaIsPlaying());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/html/parser/html_construction_site.cc b/third_party/blink/renderer/core/html/parser/html_construction_site.cc
index 2ce68e9..bd2cc5f 100644
--- a/third_party/blink/renderer/core/html/parser/html_construction_site.cc
+++ b/third_party/blink/renderer/core/html/parser/html_construction_site.cc
@@ -62,7 +62,6 @@
 #include "third_party/blink/renderer/core/loader/frame_loader.h"
 #include "third_party/blink/renderer/core/script/ignore_destructive_write_count_incrementer.h"
 #include "third_party/blink/renderer/core/svg/svg_script_element.h"
-#include "third_party/blink/renderer/platform/bindings/microtask.h"
 #include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
diff --git a/third_party/blink/renderer/core/layout/ng/custom/css_layout_definition.cc b/third_party/blink/renderer/core/layout/ng/custom/css_layout_definition.cc
index dca8a07b..43d8c54 100644
--- a/third_party/blink/renderer/core/layout/ng/custom/css_layout_definition.cc
+++ b/third_party/blink/renderer/core/layout/ng/custom/css_layout_definition.cc
@@ -28,7 +28,6 @@
 #include "third_party/blink/renderer/core/layout/ng/custom/custom_layout_scope.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h"
-#include "third_party/blink/renderer/platform/bindings/microtask.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/v8_binding_macros.h"
 #include "third_party/blink/renderer/platform/bindings/v8_object_constructor.h"
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc
index 1b8c950..11a93e18 100644
--- a/third_party/blink/renderer/core/loader/document_loader.cc
+++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -117,7 +117,6 @@
 #include "third_party/blink/renderer/core/timing/soft_navigation_heuristics.h"
 #include "third_party/blink/renderer/core/timing/window_performance.h"
 #include "third_party/blink/renderer/core/xml/document_xslt.h"
-#include "third_party/blink/renderer/platform/bindings/microtask.h"
 #include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
 #include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
 #include "third_party/blink/renderer/platform/fonts/font_performance.h"
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc
index 5037098..b0c3dfe 100644
--- a/third_party/blink/renderer/core/loader/frame_loader.cc
+++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -109,7 +109,6 @@
 #include "third_party/blink/renderer/core/svg/graphics/svg_image.h"
 #include "third_party/blink/renderer/core/xml/parser/xml_document_parser.h"
 #include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
-#include "third_party/blink/renderer/platform/bindings/microtask.h"
 #include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
 #include "third_party/blink/renderer/platform/bindings/v8_dom_activity_logger.h"
 #include "third_party/blink/renderer/platform/exported/wrapped_resource_request.h"
diff --git a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
index f1fa7410..86d75fa9 100644
--- a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
+++ b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
@@ -32,7 +32,6 @@
 #include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
 #include "third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h"
-#include "third_party/blink/renderer/platform/bindings/microtask.h"
 #include "third_party/blink/renderer/platform/bindings/no_alloc_direct_call_host.h"
 #include "third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h"
 #include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
diff --git a/third_party/blink/renderer/core/script/html_parser_script_runner.cc b/third_party/blink/renderer/core/script/html_parser_script_runner.cc
index be17956..07e08e6 100644
--- a/third_party/blink/renderer/core/script/html_parser_script_runner.cc
+++ b/third_party/blink/renderer/core/script/html_parser_script_runner.cc
@@ -39,7 +39,6 @@
 #include "third_party/blink/renderer/core/script/html_parser_script_runner_host.h"
 #include "third_party/blink/renderer/core/script/script_loader.h"
 #include "third_party/blink/renderer/core/script/script_runner.h"
-#include "third_party/blink/renderer/platform/bindings/microtask.h"
 #include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
 #include "third_party/blink/renderer/platform/instrumentation/histogram.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
diff --git a/third_party/blink/renderer/core/streams/transform_stream_test.cc b/third_party/blink/renderer/core/streams/transform_stream_test.cc
index 8ebf87b4..f5d9f31 100644
--- a/third_party/blink/renderer/core/streams/transform_stream_test.cc
+++ b/third_party/blink/renderer/core/streams/transform_stream_test.cc
@@ -22,7 +22,6 @@
 #include "third_party/blink/renderer/core/streams/transform_stream_transformer.h"
 #include "third_party/blink/renderer/core/streams/writable_stream.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/blink/renderer/platform/bindings/microtask.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/to_v8.h"
 #include "third_party/blink/renderer/platform/bindings/v8_binding.h"
diff --git a/third_party/blink/renderer/core/workers/threaded_worklet_test.cc b/third_party/blink/renderer/core/workers/threaded_worklet_test.cc
index 623bd36e..00eb640c 100644
--- a/third_party/blink/renderer/core/workers/threaded_worklet_test.cc
+++ b/third_party/blink/renderer/core/workers/threaded_worklet_test.cc
@@ -169,7 +169,8 @@
   WorkerOrWorkletGlobalScope* CreateWorkerGlobalScope(
       std::unique_ptr<GlobalScopeCreationParams> creation_params) final {
     auto* global_scope = MakeGarbageCollected<FakeWorkletGlobalScope>(
-        std::move(creation_params), GetWorkerReportingProxy(), this);
+        std::move(creation_params), GetWorkerReportingProxy(), this,
+        /*create_microtask_queue=*/true);
     EXPECT_FALSE(global_scope->IsMainThreadWorkletGlobalScope());
     EXPECT_TRUE(global_scope->IsThreadedWorkletGlobalScope());
     return global_scope;
diff --git a/third_party/blink/renderer/core/workers/worker_global_scope.cc b/third_party/blink/renderer/core/workers/worker_global_scope.cc
index 69e01fb..7a30ea77 100644
--- a/third_party/blink/renderer/core/workers/worker_global_scope.cc
+++ b/third_party/blink/renderer/core/workers/worker_global_scope.cc
@@ -70,7 +70,6 @@
 #include "third_party/blink/renderer/core/workers/worker_thread.h"
 #include "third_party/blink/renderer/platform/bindings/exception_messages.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/blink/renderer/platform/bindings/microtask.h"
 #include "third_party/blink/renderer/platform/bindings/source_location.h"
 #include "third_party/blink/renderer/platform/fonts/font_matching_metrics.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
diff --git a/third_party/blink/renderer/core/workers/worker_thread.cc b/third_party/blink/renderer/core/workers/worker_thread.cc
index a26fb82..b20c2286 100644
--- a/third_party/blink/renderer/core/workers/worker_thread.cc
+++ b/third_party/blink/renderer/core/workers/worker_thread.cc
@@ -56,7 +56,6 @@
 #include "third_party/blink/renderer/core/workers/worker_clients.h"
 #include "third_party/blink/renderer/core/workers/worker_global_scope.h"
 #include "third_party/blink/renderer/core/workers/worker_reporting_proxy.h"
-#include "third_party/blink/renderer/platform/bindings/microtask.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h"
 #include "third_party/blink/renderer/platform/loader/fetch/worker_resource_timing_notifier.h"
diff --git a/third_party/blink/renderer/core/workers/worklet_global_scope.cc b/third_party/blink/renderer/core/workers/worklet_global_scope.cc
index 8c08ef4..22add1b 100644
--- a/third_party/blink/renderer/core/workers/worklet_global_scope.cc
+++ b/third_party/blink/renderer/core/workers/worklet_global_scope.cc
@@ -53,14 +53,15 @@
 WorkletGlobalScope::WorkletGlobalScope(
     std::unique_ptr<GlobalScopeCreationParams> creation_params,
     WorkerReportingProxy& reporting_proxy,
-    WorkerThread* worker_thread)
+    WorkerThread* worker_thread,
+    bool create_microtask_queue)
     : WorkletGlobalScope(std::move(creation_params),
                          reporting_proxy,
                          worker_thread->GetIsolate(),
                          ThreadType::kOffMainThread,
                          nullptr /* frame */,
                          worker_thread,
-                         false /* create_microtask_queue */) {}
+                         create_microtask_queue) {}
 
 // Partial implementation of the "set up a worklet environment settings object"
 // algorithm:
diff --git a/third_party/blink/renderer/core/workers/worklet_global_scope.h b/third_party/blink/renderer/core/workers/worklet_global_scope.h
index 2922916..ba519f4 100644
--- a/third_party/blink/renderer/core/workers/worklet_global_scope.h
+++ b/third_party/blink/renderer/core/workers/worklet_global_scope.h
@@ -125,9 +125,12 @@
 
   // Constructs an instance as a threaded worklet. Must be called on a worker
   // thread.
+  // When |create_microtask_queue| is true, creates a microtask queue separated
+  // from the Isolate's default microtask queue.
   WorkletGlobalScope(std::unique_ptr<GlobalScopeCreationParams>,
                      WorkerReportingProxy&,
-                     WorkerThread*);
+                     WorkerThread*,
+                     bool create_microtask_queue);
 
   const BrowserInterfaceBrokerProxy& GetBrowserInterfaceBroker() const override;
 
diff --git a/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.cc b/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.cc
index 5113a7a..6bc8305 100644
--- a/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.cc
+++ b/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.cc
@@ -23,6 +23,7 @@
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/v8_binding_macros.h"
 #include "third_party/blink/renderer/platform/bindings/v8_object_constructor.h"
+#include "third_party/blink/renderer/platform/scheduler/common/features.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 
 #include "v8/include/v8.h"
@@ -49,7 +50,10 @@
     WorkerThread* thread)
     : WorkletGlobalScope(std::move(creation_params),
                          thread->GetWorkerReportingProxy(),
-                         thread) {}
+                         thread,
+                         /*create_microtask_queue=*/
+                         base::FeatureList::IsEnabled(
+                             scheduler::kMicrotaskQueuePerAnimationWorklet)) {}
 
 AnimationWorkletGlobalScope::~AnimationWorkletGlobalScope() = default;
 
diff --git a/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_characteristic.cc b/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_characteristic.cc
index c9b357a..f626ae0e 100644
--- a/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_characteristic.cc
+++ b/third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_characteristic.cc
@@ -24,7 +24,6 @@
 #include "third_party/blink/renderer/modules/bluetooth/bluetooth_remote_gatt_utils.h"
 #include "third_party/blink/renderer/modules/bluetooth/bluetooth_uuid.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/blink/renderer/platform/bindings/microtask.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/scheduler/public/event_loop.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
diff --git a/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.cc b/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.cc
index 9770366..04ea4042 100644
--- a/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.cc
+++ b/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.cc
@@ -29,6 +29,7 @@
 #include "third_party/blink/renderer/platform/bindings/callback_method_retriever.h"
 #include "third_party/blink/renderer/platform/bindings/v8_binding_macros.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/scheduler/common/features.h"
 #include "third_party/blink/renderer/platform/wtf/wtf.h"
 
 namespace blink {
@@ -125,14 +126,19 @@
     : WorkletGlobalScope(std::move(creation_params),
                          reporting_proxy,
                          frame,
-                         /*create_microtask_queue=*/false) {}
+                         /*create_microtask_queue=*/
+                         base::FeatureList::IsEnabled(
+                             scheduler::kMicrotaskQueuePerPaintWorklet)) {}
 
 PaintWorkletGlobalScope::PaintWorkletGlobalScope(
     std::unique_ptr<GlobalScopeCreationParams> creation_params,
     WorkerThread* thread)
     : WorkletGlobalScope(std::move(creation_params),
                          thread->GetWorkerReportingProxy(),
-                         thread) {}
+                         thread,
+                         /*create_microtask_queue=*/
+                         base::FeatureList::IsEnabled(
+                             scheduler::kMicrotaskQueuePerPaintWorklet)) {}
 
 PaintWorkletGlobalScope::~PaintWorkletGlobalScope() = default;
 
diff --git a/third_party/blink/renderer/modules/file_system_access/data_transfer_item_file_system_access.cc b/third_party/blink/renderer/modules/file_system_access/data_transfer_item_file_system_access.cc
index 8ba9904..005ef53a 100644
--- a/third_party/blink/renderer/modules/file_system_access/data_transfer_item_file_system_access.cc
+++ b/third_party/blink/renderer/modules/file_system_access/data_transfer_item_file_system_access.cc
@@ -9,9 +9,7 @@
 #include "third_party/blink/public/mojom/file_system_access/file_system_access_data_transfer_token.mojom-blink.h"
 #include "third_party/blink/public/mojom/file_system_access/file_system_access_directory_handle.mojom-blink.h"
 #include "third_party/blink/public/mojom/file_system_access/file_system_access_error.mojom-blink.h"
-#include "third_party/blink/public/mojom/file_system_access/file_system_access_file_handle.mojom-blink.h"
 #include "third_party/blink/public/mojom/file_system_access/file_system_access_manager.mojom-blink.h"
-#include "third_party/blink/public/mojom/file_system_access/file_system_access_transfer_token.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/core/clipboard/data_object_item.h"
@@ -19,12 +17,9 @@
 #include "third_party/blink/renderer/core/clipboard/data_transfer_item.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/modules/file_system_access/file_system_access_error.h"
-#include "third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.h"
-#include "third_party/blink/renderer/modules/file_system_access/file_system_file_handle.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
 
@@ -68,10 +63,18 @@
       WTF::BindOnce(
           [](mojo::Remote<mojom::blink::FileSystemAccessManager>,
              ScriptPromiseResolver* resolver,
+             mojom::blink::FileSystemAccessErrorPtr result,
              mojom::blink::FileSystemAccessEntryPtr entry) {
             ScriptState* script_state = resolver->GetScriptState();
             if (!script_state)
               return;
+
+            if (result->status != mojom::blink::FileSystemAccessStatus::kOk) {
+              DCHECK(entry.is_null());
+              file_system_access_error::Reject(resolver, *result);
+              return;
+            }
+
             resolver->Resolve(FileSystemHandle::CreateFromMojoEntry(
                 std::move(entry), ExecutionContext::From(script_state)));
           },
diff --git a/third_party/blink/renderer/modules/locks/lock_manager.cc b/third_party/blink/renderer/modules/locks/lock_manager.cc
index 6e2bdaa..d9bac2b 100644
--- a/third_party/blink/renderer/modules/locks/lock_manager.cc
+++ b/third_party/blink/renderer/modules/locks/lock_manager.cc
@@ -24,7 +24,6 @@
 #include "third_party/blink/renderer/core/frame/web_feature.h"
 #include "third_party/blink/renderer/core/workers/worker_global_scope.h"
 #include "third_party/blink/renderer/modules/locks/lock.h"
-#include "third_party/blink/renderer/platform/bindings/microtask.h"
 #include "third_party/blink/renderer/platform/bindings/name_client.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
diff --git a/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc b/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc
index 587c761..00f480b4 100644
--- a/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc
+++ b/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc
@@ -13,7 +13,6 @@
 #include "third_party/blink/renderer/core/execution_context/agent.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h"
-#include "third_party/blink/renderer/platform/bindings/microtask.h"
 #include "third_party/blink/renderer/platform/scheduler/public/event_loop.h"
 #include "third_party/blink/renderer/platform/scheduler/public/thread.h"
 #include "third_party/blink/renderer/platform/web_test_support.h"
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 efef6a9..cf2005f 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
@@ -11,6 +11,7 @@
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_audio_device.h"
 #include "third_party/blink/public/platform/web_audio_latency_hint.h"
+#include "third_party/blink/public/platform/web_audio_sink_descriptor.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_context_options.h"
 #include "third_party/blink/renderer/core/dom/document.h"
@@ -54,6 +55,7 @@
 class AudioContextAutoplayTestPlatform : public TestingPlatformSupport {
  public:
   std::unique_ptr<WebAudioDevice> CreateAudioDevice(
+      const WebAudioSinkDescriptor& sink_descriptor,
       unsigned number_of_output_channels,
       const WebAudioLatencyHint& latency_hint,
       WebAudioDevice::RenderCallback*) override {
diff --git a/third_party/blink/renderer/modules/webaudio/audio_context_test.cc b/third_party/blink/renderer/modules/webaudio/audio_context_test.cc
index cf1e00f..bfae7d6 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_context_test.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_context_test.cc
@@ -11,6 +11,7 @@
 #include "third_party/blink/public/mojom/frame/lifecycle.mojom-blink.h"
 #include "third_party/blink/public/platform/web_audio_device.h"
 #include "third_party/blink/public/platform/web_audio_latency_hint.h"
+#include "third_party/blink/public/platform/web_audio_sink_descriptor.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_union_audiocontextlatencycategory_double.h"
 #include "third_party/blink/renderer/core/core_initializer.h"
 #include "third_party/blink/renderer/core/dom/document.h"
@@ -48,6 +49,7 @@
 class AudioContextTestPlatform : public TestingPlatformSupport {
  public:
   std::unique_ptr<WebAudioDevice> CreateAudioDevice(
+      const WebAudioSinkDescriptor& sink_descriptor,
       unsigned number_of_output_channels,
       const WebAudioLatencyHint& latency_hint,
       WebAudioDevice::RenderCallback*) override {
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.cc b/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.cc
index 89eaeb5..ce05890 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.cc
@@ -22,6 +22,7 @@
 #include "third_party/blink/renderer/modules/webaudio/audio_worklet_processor_definition.h"
 #include "third_party/blink/renderer/modules/webaudio/cross_thread_audio_worklet_processor_info.h"
 #include "third_party/blink/renderer/platform/bindings/callback_method_retriever.h"
+#include "third_party/blink/renderer/platform/scheduler/common/features.h"
 
 namespace blink {
 
@@ -30,7 +31,10 @@
     WorkerThread* thread)
     : WorkletGlobalScope(std::move(creation_params),
                          thread->GetWorkerReportingProxy(),
-                         thread) {
+                         thread,
+                         /*create_microtask_queue=*/
+                         base::FeatureList::IsEnabled(
+                             scheduler::kMicrotaskQueuePerAudioWorklet)) {
   // Audio is prone to jank introduced by e.g. the garbage collector. Workers
   // are generally put in a background mode (as they are non-visible). Audio is
   // an exception here, requiring low-latency behavior similar to any visible
diff --git a/third_party/blink/renderer/modules/webgpu/dawn_object.cc b/third_party/blink/renderer/modules/webgpu/dawn_object.cc
index 984c080..b43e20c 100644
--- a/third_party/blink/renderer/modules/webgpu/dawn_object.cc
+++ b/third_party/blink/renderer/modules/webgpu/dawn_object.cc
@@ -6,7 +6,6 @@
 
 #include "gpu/command_buffer/client/webgpu_interface.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
-#include "third_party/blink/renderer/platform/bindings/microtask.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_device.cc b/third_party/blink/renderer/modules/webgpu/gpu_device.cc
index 9e060c8f..648a4d6 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_device.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_device.cc
@@ -44,7 +44,6 @@
 #include "third_party/blink/renderer/modules/webgpu/gpu_uncaptured_error_event.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_validation_error.h"
 #include "third_party/blink/renderer/modules/webgpu/string_utils.h"
-#include "third_party/blink/renderer/platform/bindings/microtask.h"
 #include "third_party/blink/renderer/platform/heap/thread_state.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 77dc595..2aee75c 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -397,8 +397,6 @@
     "bindings/extensions_registry.h",
     "bindings/idl_member_installer.cc",
     "bindings/idl_member_installer.h",
-    "bindings/microtask.cc",
-    "bindings/microtask.h",
     "bindings/multi_worlds_v8_reference.cc",
     "bindings/multi_worlds_v8_reference.h",
     "bindings/name_client.h",
diff --git a/third_party/blink/renderer/platform/audio/audio_destination.cc b/third_party/blink/renderer/platform/audio/audio_destination.cc
index 4f542916..670d5dd 100644
--- a/third_party/blink/renderer/platform/audio/audio_destination.cc
+++ b/third_party/blink/renderer/platform/audio/audio_destination.cc
@@ -38,6 +38,7 @@
 #include "third_party/blink/public/platform/modules/webrtc/webrtc_logging.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_audio_latency_hint.h"
+#include "third_party/blink/public/platform/web_audio_sink_descriptor.h"
 #include "third_party/blink/renderer/platform/audio/audio_utilities.h"
 #include "third_party/blink/renderer/platform/audio/push_pull_fifo.h"
 #include "third_party/blink/renderer/platform/audio/vector_math.h"
@@ -105,8 +106,9 @@
   SendLogMessage(
       String::Format("%s => (FIFO size=%u bytes)", __func__, fifo_->length()));
 
+  WebAudioSinkDescriptor sink_descriptor(WebString::FromASCII(std::string()));
   web_audio_device_ = Platform::Current()->CreateAudioDevice(
-      number_of_output_channels, latency_hint, this);
+      sink_descriptor, number_of_output_channels, latency_hint, this);
   DCHECK(web_audio_device_);
 
   callback_buffer_size_ = web_audio_device_->FramesPerBuffer();
diff --git a/third_party/blink/renderer/platform/audio/audio_destination_test.cc b/third_party/blink/renderer/platform/audio/audio_destination_test.cc
index 1b532a55..622da9a 100644
--- a/third_party/blink/renderer/platform/audio/audio_destination_test.cc
+++ b/third_party/blink/renderer/platform/audio/audio_destination_test.cc
@@ -37,6 +37,7 @@
 class TestPlatform : public TestingPlatformSupport {
  public:
   std::unique_ptr<WebAudioDevice> CreateAudioDevice(
+      const WebAudioSinkDescriptor& sink_descriptor,
       unsigned number_of_output_channels,
       const WebAudioLatencyHint& latency_hint,
       WebAudioDevice::RenderCallback*) override {
diff --git a/third_party/blink/renderer/platform/bindings/microtask.cc b/third_party/blink/renderer/platform/bindings/microtask.cc
deleted file mode 100644
index 81eae4b..0000000
--- a/third_party/blink/renderer/platform/bindings/microtask.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer
- *    in the documentation and/or other materials provided with the
- *    distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- *    may be used to endorse or promote products derived from this
- *    software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/platform/bindings/microtask.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/memory/ptr_util.h"
-
-namespace blink {
-
-static void MicrotaskFunctionCallback(void* data) {
-  std::unique_ptr<base::OnceClosure> task =
-      base::WrapUnique(static_cast<base::OnceClosure*>(data));
-  std::move(*task).Run();
-}
-
-void Microtask::EnqueueMicrotask(base::OnceClosure callback) {
-  v8::Isolate* isolate = v8::Isolate::GetCurrent();
-  isolate->EnqueueMicrotask(
-      &MicrotaskFunctionCallback,
-      static_cast<void*>(new base::OnceClosure(std::move(callback))));
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/platform/bindings/microtask.h b/third_party/blink/renderer/platform/bindings/microtask.h
deleted file mode 100644
index 953ecf3..0000000
--- a/third_party/blink/renderer/platform/bindings/microtask.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer
- *    in the documentation and/or other materials provided with the
- *    distribution.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- *    may be used to endorse or promote products derived from this
- *    software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_MICROTASK_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_MICROTASK_H_
-
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/functional.h"
-#include "v8/include/v8.h"
-
-namespace blink {
-
-// C++ calls into script contexts which are "owned" by blink (created in a
-// process where WebKit.cpp initializes v8) must declare their type:
-//
-//   1. Calls into page/author script from a frame
-//   2. Calls into page/author script from a worker
-//   3. Calls into internal script (typically setup/teardown work)
-//
-// Debug-time checking of this is enforced via v8::MicrotasksScope.
-//
-// Calls of type (1) should generally go through ScriptController, as inspector
-// instrumentation is needed. ScriptController allocates V8RecursionScope for
-// you.
-//
-// Calls of type (2) should always stack-allocate a
-// v8::MicrotasksScope(kRunMicrtoasks) in the same block as the call into
-// script.
-//
-// Calls of type (3) should stack allocate a
-// v8::MicrotasksScope(kDoNotRunMicrotasks) -- this skips work that is spec'd to
-// happen at the end of the outer-most script stack frame of calls into page
-// script:
-// http://www.whatwg.org/specs/web-apps/current-work/#perform-a-microtask-checkpoint
-class PLATFORM_EXPORT Microtask {
-  STATIC_ONLY(Microtask);
-
- public:
-  // TODO(yukishiino): Make all microtasks pass in the ScriptState they want to be
-  // executed in. Until then, all microtasks have to keep track of their
-  // ScriptState themselves.
-  static void EnqueueMicrotask(base::OnceClosure);
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_MICROTASK_H_
diff --git a/third_party/blink/renderer/platform/graphics/gpu/DEPS b/third_party/blink/renderer/platform/graphics/gpu/DEPS
index a2e8e5d..e311d320 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/DEPS
+++ b/third_party/blink/renderer/platform/graphics/gpu/DEPS
@@ -14,7 +14,6 @@
     "+gpu/config/gpu_driver_bug_workaround_type.h",
     "+gpu/config/gpu_feature_info.h",
     "+gpu/webgpu/callback.h",
-    "+third_party/blink/renderer/platform/bindings/microtask.h",
     "+ui/gfx/gpu_fence.h",
     "+ui/gl/gpu_preference.h",
 ]
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc
index 7131ec719..a19098d5 100644
--- a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc
@@ -702,7 +702,7 @@
 #endif
   encoder_info_.supports_native_handle = true;
   encoder_info_.implementation_name = "ExternalEncoder";
-  encoder_info_.has_trusted_rate_controller = true;
+  encoder_info_.has_trusted_rate_controller = false;
   encoder_info_.is_hardware_accelerated = true;
   encoder_info_.is_qp_trusted = true;
   encoder_info_.fps_allocation[0] = {
diff --git a/third_party/blink/renderer/platform/scheduler/common/features.h b/third_party/blink/renderer/platform/scheduler/common/features.h
index d38ecb6..d05154c 100644
--- a/third_party/blink/renderer/platform/scheduler/common/features.h
+++ b/third_party/blink/renderer/platform/scheduler/common/features.h
@@ -175,6 +175,18 @@
              "BlinkSchedulerMicroTaskQueuePerWindowAgent",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kMicrotaskQueuePerPaintWorklet,
+             "BlinkSchedulerMicroTaskQueuePerPaintWorklet",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+BASE_FEATURE(kMicrotaskQueuePerAnimationWorklet,
+             "BlinkSchedulerMicroTaskQueuePerAnimationWorklet",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+BASE_FEATURE(kMicrotaskQueuePerAudioWorklet,
+             "BlinkSchedulerMicroTaskQueuePerAudioWorklet",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 }  // namespace scheduler
 }  // namespace blink
 
diff --git a/third_party/blink/renderer/platform/wtf/text/README.md b/third_party/blink/renderer/platform/wtf/text/README.md
index ce8b1273..465a6b0 100644
--- a/third_party/blink/renderer/platform/wtf/text/README.md
+++ b/third_party/blink/renderer/platform/wtf/text/README.md
@@ -24,9 +24,6 @@
 reference counted character buffer. This design makes it easier to
 share the underlying character buffer between different consumers
 because multiple consumers can reference the same underlying buffer.
-The disadvantage of this design is that we need to be careful when
-mixing Strings with multithreading because the character buffer’s
-reference counting is not thread safe.
 
 
 ## Storage
@@ -210,7 +207,7 @@
 ## Atomic Strings
 
 Some `StringImpl` objects are marked as _Atomic_, which means they’re
-stored in a thread-local `HashSet` called the `AtomicString` table.
+stored in a process-wide `HashSet` called the `AtomicString` table.
 Rather than interacting directly with these anointed `StringImpl`
 objects, we usually hold pointers to them via `AtomicString` objects
 (rather than `String` objects). Using `AtomicString` rather than
@@ -222,14 +219,13 @@
 ### Construction
 
 Typically, constructing an `AtomicString` from a `String` object will
-involve a hash lookup in the `AtomicString` table for the current
-thread. If the string represented by the `String` object is not
-present in the `AtomicString` table, the `StringImpl` object from that
-`String` will be marked Atomic and added to the table. If the
-represented string is already present in the `AtomicString` table, the
-already-Atomic `StringImpl` object from the table will be used to
-construct the `AtomicString` rather than the `StringImpl` from the
-original String.
+involve a hash lookup in the `AtomicString` table. If the string
+represented by the `String` object is not present in the `AtomicString`
+table, the `StringImpl` object from that `String` will be marked Atomic
+and added to the table. If the represented string is already present in
+the `AtomicString` table, the already-Atomic `StringImpl` object from
+the table will be used to construct the `AtomicString` rather than the
+`StringImpl` from the original String.
 
 
 If you wish to construct an `AtomicString` from an array of `LChar`s
@@ -245,61 +241,26 @@
 If two `StringImpl` objects are atomic, you can compare them for
 equality by comparing their addresses rather than by comparing them
 character-by-character. The reason this works is that we maintain the
-invariant that no two Atomic `StringImpl` objects on a given thread
-represent the same string. Therefore, the two `StringImpl` objects
-represent the same string if, and only if, they are actually the same
-`StringImpl` object. We’ve overloaded `operator==` on `AtomicString`
-to let the compiler generate these optimized comparisons
-automatically.
+invariant that no two Atomic `StringImpl` objects represent the same
+string. Therefore, the two `StringImpl` objects represent the same
+string if, and only if, they are actually the same `StringImpl` object.
+We’ve overloaded `operator==` on `AtomicString` to let the compiler
+generate these optimized comparisons automatically.
 
 ### Deduplication
 
-Because there are no duplicate Atomic `StringImpl` objects on a given
-thread, `AtomicString`s are useful for coalescing duplicate strings
-into a single `StringImpl` object, saving memory. Unfortunately,
-`AtomicString`s are thread-specific and cannot be used to coalesce
-duplicate strings across threads.
-
-## Threading
-
-### Isolated copies
-
-String objects that you construct yourself are not thread-safe. The
-underlying `StringImpl` object can be shared only by `String` objects
-on the same thread because the `StringImpl`’s reference count isn’t
-incremented or decremented atomically.
-
-
-In some limited cases, you can safely send a `String` from one thread
-to another. In order for that to be safe, you need to make sure that
-the underlying `StringImpl` object has exactly one reference---the one
-you’re sending to another thread. If there is only one outstanding
-reference to the `StringImpl`, then there won’t be any reference count
-data races. The easiest way to get a `StringImpl` object with only one
-reference is to call `String::IsolatedCopy()`. You can check that a
-given `String` is safe to send to another thread by calling
-`String::IsSafeToSendToAnotherThread()`, typically in a `DCHECK`.
-
-
-If you look at the implementation of `IsSafeToSendToAnotherThread()`,
-you’ll notice that it always returns false if the `StringImpl` is
-Atomic, regardless of the reference count. That’s because Atomic
-`StringImpl` objects are not safe to send to another thread because
-they’re associated with an `AtomicString` table local to the current
-thread. If you do send an `AtomicString` to another thread and the
-`StringImpl` object is destructed on that thread, it will try to
-remove itself from that thread’s `AtomicString` table rather than from
-the original thread’s `AtomicString` table.
+Because there are no duplicate Atomic `StringImpl` objects,
+`AtomicString`s are useful for coalescing duplicate strings
+into a single `StringImpl` object, saving memory.
 
 ### Static Strings
 
 At startup, we create a number of _Static_ `StringImpl` objects that
-are safe to use from any thread. These `StringImpl` objects maintain
-the invariant that the least significant bit of their reference count
-is always one, which means their reference count never reaches zero
-and they are never deallocated. In addition to preventing their
-deallocation, we also pre-populate the hash value to ensure that
-Static `StringImpl` objects are otherwise immutable.
+maintain the invariant that the least significant bit of their
+reference count is always one, which means their reference count
+never reaches zero and they are never deallocated. In addition to
+preventing their deallocation, we also pre-populate the hash value
+to ensure that Static `StringImpl` objects are otherwise immutable.
 
 
 We first introduced these Static strings for the threaded HTML parser,
diff --git a/third_party/blink/web_tests/fast/scrolling/overflow-scrollability.html b/third_party/blink/web_tests/fast/scrolling/overflow-scrollability.html
index 7ba20bcf..c15a887f 100644
--- a/third_party/blink/web_tests/fast/scrolling/overflow-scrollability.html
+++ b/third_party/blink/web_tests/fast/scrolling/overflow-scrollability.html
@@ -65,13 +65,7 @@
 
 <script>
   const mouse = GestureSourceType.MOUSE_INPUT;
-  const pixelsToScroll = pixelsPerTick();
-
-  async function waitForScroll(scrollPosFunc, target, errorMesage) {
-    await waitFor(() => {
-      return Math.abs(scrollPosFunc() - target) < 0.01;
-    }, errorMesage);
-  }
+  const pixelsToScroll = 10;
 
   async function testScrollable(div_id, can_scroll) {
     let div = document.getElementById(div_id);
@@ -86,13 +80,9 @@
     await smoothScroll(pixelsToScroll, x, y, mouse, 'down',
                        SPEED_INSTANT, false /* precise_scrolling_deltas */);
     let assertDescription = `${div_id} vertical scroll failed`;
-    if (can_scroll) {
-      waitForScroll(() => div.scrollTop, expectedScroll.y,
-                    assertDescription);
-    } else {
-      // Wait a few frames before checking to ensure the div doesn't scroll.
-      await raf();
-      await raf();
+    if (can_scroll)
+      assert_approx_equals(div.scrollTop, expectedScroll.y, 0.01, assertDescription);
+    else {
       assert_equals(div.scrollTop, 0, assertDescription);
     }
 
@@ -100,12 +90,8 @@
                        SPEED_INSTANT, false /* precise_scrolling_deltas */);
     assertDescription = `${div_id} horizontal scroll failed`;
     if (can_scroll) {
-      waitForScroll(() => div.scrollLeft, expectedScroll.x,
-                    assertDescription);
       assert_approx_equals(div.scrollLeft, expectedScroll.x, 0.01, assertDescription);
     } else {
-      await raf();
-      await raf();
       assert_equals(div.scrollLeft, 0, assertDescription);
     }
   }
@@ -127,4 +113,4 @@
     }, 'This tests that scrollable areas with the appropriate overflow mode set'
       + ' are in fact scrollable by the user.');
   };
-</script>
+</script>
\ No newline at end of file
diff --git a/third_party/omnibox_proto/README.chromium b/third_party/omnibox_proto/README.chromium
index 594f50f..6987ce4c 100644
--- a/third_party/omnibox_proto/README.chromium
+++ b/third_party/omnibox_proto/README.chromium
@@ -1,8 +1,8 @@
 Name: Omnibox Protos
 Short Name: omnibox_proto
 URL: This is the canonical public repository
-Version: 479680458
-Date: 2022/10/07 UTC
+Version: 480506726
+Date: 2022/10/12 UTC
 License: BSD
 Security Critical: Yes
 
diff --git a/third_party/omnibox_proto/groups.proto b/third_party/omnibox_proto/groups.proto
index 22e4bed2..53bb8b9 100644
--- a/third_party/omnibox_proto/groups.proto
+++ b/third_party/omnibox_proto/groups.proto
@@ -62,6 +62,7 @@
 // be removed or renumbered.
 enum GroupId {
   GROUP_INVALID = -1;
+
   // Reserved for Polaris zero-prefix suggestions.
   // Produced by ZeroSuggestProvider.
   GROUP_PREVIOUS_SEARCH_RELATED = 10000;
@@ -71,16 +72,24 @@
   GROUP_RELATED_QUERIES = 10004;
   GROUP_VISITED_DOC_RELATED = 10005;
   GROUP_POLARIS_RESERVED_MAX = 19999;
+
   // Mobile-specific auxiliary suggestions. These suggestions are placed on top
   // of any other content.
   GROUP_MOBILE_SEARCH_READY_OMNIBOX = 30000;
   GROUP_MOBILE_MOST_VISITED = 30001;
   GROUP_MOBILE_CLIPBOARD = 30002;
+
   // Reserved for personalized zero-prefix suggestions.
   // Produced by ZeroSuggestProvider and LocalHistoryZeroSuggestProvider.
   GROUP_PERSONALIZED_ZERO_SUGGEST = 40000;
-  // Produced by HistoryClusterProvider.
-  GROUP_HISTORY_CLUSTER = 50000;
+
+  // Cross platform suggestions with vanilla visual representation (i.e.
+  // vertical, primary column, and no header), but useful for sorting.
+  GROUP_STARTER_PACK = 50000;
+  GROUP_SEARCH = 50001;
+  GROUP_OTHER_NAVS = 50002;  // E.g., bookmarks, history, etc.
+  GROUP_DOCUMENT = 50003;    // E.g., Drive docs, slides, sheets, etc.
+  GROUP_HISTORY_CLUSTER = 50004;
 }
 
 // Suggestion group sections determine the order in which suggestion groups
@@ -123,4 +132,12 @@
   SECTION_REMOTE_ZPS_8 = 11;
   SECTION_REMOTE_ZPS_9 = 12;
   SECTION_REMOTE_ZPS_10 = 13;
+
+  // Cross platform suggestions with vanilla visual representation (i.e.
+  // vertical, primary column, and no header), but useful for sorting.
+  SECTION_STARTER_PACK = 100;
+  SECTION_SEARCH = 101;
+  SECTION_OTHER_NAVS = 102;
+  SECTION_DOCUMENT = 103;
+  SECTION_HISTORY_CLUSTER = 104;
 }
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 4728c74c..a418232a 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -117,7 +117,7 @@
       'android-weblayer-with-aosp-webview-x86-rel': 'android_release_bot_minimal_symbols_x86_fastbuild_resource_allowlisting_disable_proguard_chrome_google',
       # Use webview_monochrome as this builder triggers tests on Android O & P
       'android-weblayer-x86-rel': 'android_release_bot_minimal_symbols_x86_fastbuild_disable_proguard_webview_monochrome',
-      'android-x86-rel': 'android_release_bot_minimal_symbols_x86_fastbuild_webview_trichrome_webview_shell_reclient',
+      'android-x86-rel': 'android_release_bot_minimal_symbols_x86_fastbuild_webview_trichrome_reclient',
     },
 
     'chromium.android.fyi': {
@@ -131,7 +131,7 @@
       'android-weblayer-pie-x86-wpt-fyi-rel': 'android_release_bot_minimal_symbols_x86_fastbuild_webview_monochrome_reclient',
       'android-weblayer-pie-x86-wpt-smoketest': 'android_release_bot_minimal_symbols_x86_fastbuild_webview_monochrome_reclient',
       'android-weblayer-with-aosp-webview-x86-fyi-rel': 'android_release_bot_minimal_symbols_x86_fastbuild_resource_allowlisting_disable_proguard_chrome_google_reclient',
-      'android-webview-pie-x86-wpt-fyi-rel': 'android_release_bot_minimal_symbols_x86_fastbuild_webview_monochrome_webview_shell_reclient',
+      'android-webview-pie-x86-wpt-fyi-rel': 'android_release_bot_minimal_symbols_x86_fastbuild_webview_monochrome_reclient',
     },
 
     'chromium.angle': {
@@ -1589,7 +1589,7 @@
     ],
 
     'android_debug_static_bot_x86_reclient': [
-      'android', 'debug_static_bot_reclient', 'x86',
+      'android', 'debug_static_bot_reclient', 'x86', 'webview_shell',
     ],
 
     'android_debug_static_external_bot': [
@@ -1675,7 +1675,7 @@
     'android_release_bot_minimal_symbols_x64_fastbuild_webview_trichrome_reclient': [
       'android', 'release_bot_reclient', 'minimal_symbols', 'x64',
       'strip_debug_info', 'android_fastbuild', 'webview_trichrome',
-      'no_secondary_abi',
+      'no_secondary_abi', 'webview_shell'
     ],
 
     'android_release_bot_minimal_symbols_x86_fastbuild_disable_proguard_webview_monochrome': [
@@ -1699,6 +1699,7 @@
     'android_release_bot_minimal_symbols_x86_fastbuild_webview_monochrome_reclient': [
       'android', 'release_bot_reclient', 'minimal_symbols', 'x86',
       'strip_debug_info', 'android_fastbuild', 'webview_monochrome',
+      'webview_shell',
     ],
 
     'android_release_bot_minimal_symbols_x86_fastbuild_webview_monochrome_webview_shell': [
@@ -1706,19 +1707,10 @@
       'strip_debug_info', 'android_fastbuild', 'webview_monochrome', 'webview_shell',
     ],
 
-    'android_release_bot_minimal_symbols_x86_fastbuild_webview_monochrome_webview_shell_reclient': [
-      'android', 'release_bot_reclient', 'minimal_symbols', 'x86',
-      'strip_debug_info', 'android_fastbuild', 'webview_monochrome', 'webview_shell',
-    ],
-
     'android_release_bot_minimal_symbols_x86_fastbuild_webview_trichrome_reclient': [
       'android', 'release_bot_reclient', 'minimal_symbols', 'x86',
       'strip_debug_info', 'android_fastbuild', 'webview_trichrome',
-    ],
-
-    'android_release_bot_minimal_symbols_x86_fastbuild_webview_trichrome_webview_shell_reclient': [
-      'android', 'release_bot_reclient', 'minimal_symbols', 'x86',
-      'strip_debug_info', 'android_fastbuild', 'webview_trichrome', 'webview_shell',
+      'webview_shell',
     ],
 
     'android_release_trybot': [
@@ -1787,7 +1779,7 @@
     'android_release_trybot_x64_fastbuild_webview_trichrome': [
       'android', 'release_trybot', 'strip_debug_info', 'x64',
       'android_fastbuild', 'webview_trichrome',
-      'no_secondary_abi',
+      'no_secondary_abi', 'webview_shell',
     ],
 
     'android_release_trybot_x86_fastbuild_webview_google_invert_fieldtrials': [
@@ -1797,17 +1789,17 @@
 
     'android_release_trybot_x86_fastbuild_webview_monochrome': [
       'android', 'release_trybot', 'strip_debug_info', 'x86',
-      'android_fastbuild', 'webview_monochrome',
+      'android_fastbuild', 'webview_monochrome', 'webview_shell',
     ],
 
     'android_release_trybot_x86_fastbuild_webview_monochrome_reclient': [
       'android', 'release_trybot_reclient', 'strip_debug_info', 'x86',
-      'android_fastbuild', 'webview_monochrome',
+      'android_fastbuild', 'webview_monochrome', 'webview_shell',
     ],
 
     'android_release_trybot_x86_fastbuild_webview_trichrome': [
       'android', 'release_trybot', 'strip_debug_info', 'x86',
-      'android_fastbuild', 'webview_trichrome',
+      'android_fastbuild', 'webview_trichrome', 'webview_shell',
     ],
 
     'android_webview_google_debug_static_bot_arm64': [
@@ -2108,7 +2100,7 @@
     ],
 
     'chromeos_amd64-generic_use_fake_dbus_clients_vm_optimized_dchecks': [
-      'chromeos_amd64-generic-vm', 'use_fake_dbus_clients', 'dcheck_always_on',
+      'chromeos_amd64-generic-vm', 'use_fake_dbus_clients', 'dcheck_always_on', 'also_build_lacros_chrome_for_architecture_amd64'
     ],
 
     'chromeos_arm-generic_cfi_thin_lto_official': [
@@ -3173,7 +3165,7 @@
 
     'mac_arm64_gpu_tests_debug_bot_minimal_symbols_no_nacl_reclient': [
       'arm64', 'gpu_tests', 'static_bot_reclient', 'minimal_symbols', 'disable_nacl',
-      'dcheck_off', 'debug',
+      'dcheck_off', 'debug', 'shared'
     ],
 
     'mac_arm64_gpu_tests_release_bot_minimal_symbols_no_nacl': [
diff --git a/tools/mb/mb_config_expectations/chromium.android.fyi.json b/tools/mb/mb_config_expectations/chromium.android.fyi.json
index fb29cde..9faf531 100644
--- a/tools/mb/mb_config_expectations/chromium.android.fyi.json
+++ b/tools/mb/mb_config_expectations/chromium.android.fyi.json
@@ -56,6 +56,7 @@
       "strip_debug_info": true,
       "symbol_level": 1,
       "system_webview_package_name": "com.google.android.apps.chrome",
+      "system_webview_shell_package_name": "org.chromium.my_webview_shell",
       "target_cpu": "x86",
       "target_os": "android",
       "use_remoteexec": true
@@ -120,6 +121,7 @@
       "strip_debug_info": true,
       "symbol_level": 1,
       "system_webview_package_name": "com.google.android.apps.chrome",
+      "system_webview_shell_package_name": "org.chromium.my_webview_shell",
       "target_cpu": "x86",
       "target_os": "android",
       "use_remoteexec": true
@@ -137,6 +139,7 @@
       "strip_debug_info": true,
       "symbol_level": 1,
       "system_webview_package_name": "com.google.android.apps.chrome",
+      "system_webview_shell_package_name": "org.chromium.my_webview_shell",
       "target_cpu": "x86",
       "target_os": "android",
       "use_remoteexec": true
@@ -154,6 +157,7 @@
       "strip_debug_info": true,
       "symbol_level": 1,
       "system_webview_package_name": "com.google.android.apps.chrome",
+      "system_webview_shell_package_name": "org.chromium.my_webview_shell",
       "target_cpu": "x86",
       "target_os": "android",
       "use_remoteexec": true
diff --git a/tools/mb/mb_config_expectations/chromium.android.json b/tools/mb/mb_config_expectations/chromium.android.json
index c3acf28..46dd86b 100644
--- a/tools/mb/mb_config_expectations/chromium.android.json
+++ b/tools/mb/mb_config_expectations/chromium.android.json
@@ -93,6 +93,7 @@
       "is_debug": true,
       "proprietary_codecs": true,
       "symbol_level": 1,
+      "system_webview_shell_package_name": "org.chromium.my_webview_shell",
       "target_cpu": "x86",
       "target_os": "android",
       "use_remoteexec": true
@@ -166,6 +167,7 @@
       "strip_debug_info": true,
       "symbol_level": 1,
       "system_webview_package_name": "com.google.android.webview.debug",
+      "system_webview_shell_package_name": "org.chromium.my_webview_shell",
       "target_cpu": "x86",
       "target_os": "android",
       "use_remoteexec": true
@@ -184,6 +186,7 @@
       "strip_debug_info": true,
       "symbol_level": 1,
       "system_webview_package_name": "com.google.android.webview.debug",
+      "system_webview_shell_package_name": "org.chromium.my_webview_shell",
       "target_cpu": "x64",
       "target_os": "android",
       "use_remoteexec": true
@@ -479,6 +482,7 @@
       "strip_debug_info": true,
       "symbol_level": 1,
       "system_webview_package_name": "com.google.android.apps.chrome",
+      "system_webview_shell_package_name": "org.chromium.my_webview_shell",
       "target_cpu": "x86",
       "target_os": "android",
       "use_remoteexec": true
@@ -528,6 +532,7 @@
       "strip_debug_info": true,
       "symbol_level": 1,
       "system_webview_package_name": "com.google.android.apps.chrome",
+      "system_webview_shell_package_name": "org.chromium.my_webview_shell",
       "target_cpu": "x86",
       "target_os": "android",
       "use_remoteexec": true
diff --git a/tools/mb/mb_config_expectations/chromium.fyi.json b/tools/mb/mb_config_expectations/chromium.fyi.json
index 61c4f24..6df7735 100644
--- a/tools/mb/mb_config_expectations/chromium.fyi.json
+++ b/tools/mb/mb_config_expectations/chromium.fyi.json
@@ -480,7 +480,7 @@
       "dcheck_always_on": false,
       "enable_nacl": false,
       "ffmpeg_branding": "Chrome",
-      "is_component_build": false,
+      "is_component_build": true,
       "is_debug": true,
       "proprietary_codecs": true,
       "symbol_level": 1,
@@ -677,6 +677,7 @@
       "strip_debug_info": true,
       "symbol_level": 1,
       "system_webview_package_name": "com.google.android.apps.chrome",
+      "system_webview_shell_package_name": "org.chromium.my_webview_shell",
       "target_cpu": "x86",
       "target_os": "android",
       "use_remoteexec": true
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.android.json b/tools/mb/mb_config_expectations/tryserver.chromium.android.json
index 4bc61fd..34a6ceea 100644
--- a/tools/mb/mb_config_expectations/tryserver.chromium.android.json
+++ b/tools/mb/mb_config_expectations/tryserver.chromium.android.json
@@ -28,6 +28,7 @@
       "strip_debug_info": true,
       "symbol_level": 0,
       "system_webview_package_name": "com.google.android.webview.debug",
+      "system_webview_shell_package_name": "org.chromium.my_webview_shell",
       "target_cpu": "x86",
       "target_os": "android",
       "use_goma": true
@@ -61,6 +62,7 @@
       "strip_debug_info": true,
       "symbol_level": 0,
       "system_webview_package_name": "com.google.android.webview.debug",
+      "system_webview_shell_package_name": "org.chromium.my_webview_shell",
       "target_cpu": "x64",
       "target_os": "android",
       "use_goma": true
@@ -149,6 +151,7 @@
       "strip_debug_info": true,
       "symbol_level": 0,
       "system_webview_package_name": "com.google.android.apps.chrome",
+      "system_webview_shell_package_name": "org.chromium.my_webview_shell",
       "target_cpu": "x86",
       "target_os": "android",
       "use_goma": true
@@ -600,6 +603,7 @@
       "strip_debug_info": true,
       "symbol_level": 0,
       "system_webview_package_name": "com.google.android.apps.chrome",
+      "system_webview_shell_package_name": "org.chromium.my_webview_shell",
       "target_cpu": "x86",
       "target_os": "android",
       "use_goma": true
@@ -617,6 +621,7 @@
       "strip_debug_info": true,
       "symbol_level": 0,
       "system_webview_package_name": "com.google.android.apps.chrome",
+      "system_webview_shell_package_name": "org.chromium.my_webview_shell",
       "target_cpu": "x86",
       "target_os": "android",
       "use_remoteexec": true
@@ -760,6 +765,7 @@
       "strip_debug_info": true,
       "symbol_level": 0,
       "system_webview_package_name": "com.google.android.apps.chrome",
+      "system_webview_shell_package_name": "org.chromium.my_webview_shell",
       "target_cpu": "x86",
       "target_os": "android",
       "use_goma": true
@@ -777,6 +783,7 @@
       "strip_debug_info": true,
       "symbol_level": 0,
       "system_webview_package_name": "com.google.android.apps.chrome",
+      "system_webview_shell_package_name": "org.chromium.my_webview_shell",
       "target_cpu": "x86",
       "target_os": "android",
       "use_goma": true
@@ -830,6 +837,7 @@
       "strip_debug_info": true,
       "symbol_level": 0,
       "system_webview_package_name": "com.google.android.apps.chrome",
+      "system_webview_shell_package_name": "org.chromium.my_webview_shell",
       "target_cpu": "x86",
       "target_os": "android",
       "use_goma": true
@@ -865,6 +873,7 @@
       "strip_debug_info": true,
       "symbol_level": 0,
       "system_webview_package_name": "com.google.android.apps.chrome",
+      "system_webview_shell_package_name": "org.chromium.my_webview_shell",
       "target_cpu": "x86",
       "target_os": "android",
       "use_goma": true
@@ -882,6 +891,7 @@
       "strip_debug_info": true,
       "symbol_level": 0,
       "system_webview_package_name": "com.google.android.apps.chrome",
+      "system_webview_shell_package_name": "org.chromium.my_webview_shell",
       "target_cpu": "x86",
       "target_os": "android",
       "use_goma": true
@@ -899,6 +909,7 @@
       "strip_debug_info": true,
       "symbol_level": 0,
       "system_webview_package_name": "com.google.android.webview.debug",
+      "system_webview_shell_package_name": "org.chromium.my_webview_shell",
       "target_cpu": "x86",
       "target_os": "android",
       "use_goma": true
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.chromiumos.json b/tools/mb/mb_config_expectations/tryserver.chromium.chromiumos.json
index 1c77435..bf30df1 100644
--- a/tools/mb/mb_config_expectations/tryserver.chromium.chromiumos.json
+++ b/tools/mb/mb_config_expectations/tryserver.chromium.chromiumos.json
@@ -24,6 +24,7 @@
   "chromeos-amd64-generic-rel": {
     "args_file": "//build/args/chromeos/amd64-generic-vm.gni",
     "gn_args": {
+      "also_build_lacros_chrome_for_architecture": "amd64",
       "dcheck_always_on": true,
       "is_chromeos_device": true,
       "ozone_platform_headless": true,
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 4167be0..63af492 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -9225,21 +9225,6 @@
   <int value="762"
       label="CREDIT_CARD_STANDALONE_VERIFICATION_CODE - Predictions different
              - Value agrees with both predictions"/>
-  <int value="769" label="NUMERIC_QUANTITY - Predictions equal - Value agrees"/>
-  <int value="770"
-      label="NUMERIC_QUANTITY - Predictions equal - Value disagrees"/>
-  <int value="771"
-      label="NUMERIC_QUANTITY - Predictions different - Value agrees with old
-             prediction"/>
-  <int value="772"
-      label="NUMERIC_QUANTITY - Predictions different - Value agrees with new
-             prediction"/>
-  <int value="773"
-      label="NUMERIC_QUANTITY - Predictions different - Value agrees with
-             neither prediction"/>
-  <int value="774"
-      label="NUMERIC_QUANTITY - Predictions different - Value agrees with
-             both predictions"/>
 </enum>
 
 <enum name="AutofillPredictionSource">
@@ -9520,7 +9505,6 @@
   <int value="125" label="IBAN_VALUE"/>
   <int value="126" label="CREDIT_CARD_STANDALONE_VERIFICATION_CODE"/>
   <int value="127" label="RESERVED"/>
-  <int value="128" label="NUMERIC_QUANTITY"/>
 </enum>
 
 <enum name="AutofillServerPredictionAvailability">
@@ -56674,6 +56658,7 @@
   <int value="-2129013032" label="DocumentTransition:enabled"/>
   <int value="-2128705444" label="AssistantAppSupport:enabled"/>
   <int value="-2128535212" label="GuestOsFiles:enabled"/>
+  <int value="-2127806304" label="Enable16Desks:disabled"/>
   <int value="-2127319228" label="enable-media-internals:disabled"/>
   <int value="-2126697213" label="EnablePalmSuppression:disabled"/>
   <int value="-2126275491" label="WebViewAppsPackageNamesAllowlist:disabled"/>
@@ -57071,6 +57056,7 @@
   <int value="-1913801713"
       label="UploadCrashReportsUsingJobScheduler:disabled"/>
   <int value="-1913734393" label="CrosPrivacyHub:disabled"/>
+  <int value="-1913552656" label="VCBackgroundReplace:enabled"/>
   <int value="-1912999136" label="enable-automatic-password-saving:enabled"/>
   <int value="-1911918596" label="WebviewAccelerateSmallCanvases:disabled"/>
   <int value="-1911316813" label="BlockTabUnders:disabled"/>
@@ -57730,6 +57716,7 @@
   <int value="-1510524610"
       label="RTCDisallowPlanBOutsideDeprecationTrial:enabled"/>
   <int value="-1508852757" label="CreditCardAutofillTouchBar:disabled"/>
+  <int value="-1508837668" label="VCPortraitRelighting:enabled"/>
   <int value="-1507722271" label="ImprovedDesksKeyboardShortcuts:enabled"/>
   <int value="-1506880454"
       label="SupervisedUserCommittedInterstitials:disabled"/>
@@ -58186,6 +58173,7 @@
   <int value="-1261110018" label="AllowDisableTouchpadHapticFeedback:disabled"/>
   <int value="-1260211490" label="FastPairLowPower:disabled"/>
   <int value="-1259901957" label="VrBrowserKeyboard:disabled"/>
+  <int value="-1259809702" label="Enable16Desks:enabled"/>
   <int value="-1259627326" label="AllowRepeatedUpdates:disabled"/>
   <int value="-1258141852" label="ScrollUnification:enabled"/>
   <int value="-1257822114" label="ContextMenuPopupForAllScreenSizes:disabled"/>
@@ -62962,6 +62950,7 @@
   <int value="1643700095" label="PermissionQuietChip:enabled"/>
   <int value="1643712769" label="PrintWithReducedRasterization:enabled"/>
   <int value="1644340731" label="NearbySharingSelfShareUI:enabled"/>
+  <int value="1644405691" label="VCPortraitRelighting:disabled"/>
   <int value="1645141340" label="DesksCloseAll:enabled"/>
   <int value="1645447927" label="MixedContentSiteSetting:disabled"/>
   <int value="1645479440" label="HistoryManipulationIntervention:disabled"/>
@@ -63203,6 +63192,7 @@
   <int value="1800509458" label="DriveFsChromeNetworking:disabled"/>
   <int value="1800603694" label="DXGIWaitableSwapChain:disabled"/>
   <int value="1801585504" label="ContextMenuShopWithGoogleLens:enabled"/>
+  <int value="1802821192" label="VCBackgroundReplace:disabled"/>
   <int value="1802874714" label="QueryTilesEnableQueryEditing:disabled"/>
   <int value="1803465156" label="enable-zero-suggest-most-visited"/>
   <int value="1803470125" label="SyncUSSSessions:enabled"/>
@@ -80512,7 +80502,7 @@
   <int value="-71187962" label="supervised_user.mojom.SupervisedUserCommands"/>
   <int value="191605727" label="content.mojom.PepperHost"/>
   <int value="1984681860"
-      label="chrome.mojom.OpenSearchDescriptionDocumentHandler"/>
+      label="chrome.mojom.OpenSearchDescriptionDocumentHandler (Obsolete)"/>
 </enum>
 
 <enum name="PrerenderCookieSendType">
@@ -81251,11 +81241,6 @@
   <int value="2" label="Price tracking disabled"/>
 </enum>
 
-<enum name="PrinterEditDialogActions">
-  <int value="0" label="Dialog opened"/>
-  <int value="1" label="View PPD clicked"/>
-</enum>
-
 <enum name="PrinterProtocol">
   <int value="0" label="Unknown"/>
   <int value="1" label="Universal Serial Bus (usb)"/>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index 87ed6b2d..2e4345c 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -1644,6 +1644,76 @@
   </summary>
 </histogram>
 
+<histogram name="Ash.Desks.NumberOfWindowsOnDesk_10" units="units"
+    expires_after="2023-04-23">
+  <owner>dandersson@chromium.org</owner>
+  <owner>janetmac@chromium.org</owner>
+  <summary>
+    The number of windows on the tenth desk. Emitted when a desk is removed, or
+    a window is moved to another desk.
+  </summary>
+</histogram>
+
+<histogram name="Ash.Desks.NumberOfWindowsOnDesk_11" units="units"
+    expires_after="2023-04-23">
+  <owner>dandersson@chromium.org</owner>
+  <owner>janetmac@chromium.org</owner>
+  <summary>
+    The number of windows on the eleventh desk. Emitted when a desk is removed,
+    or a window is moved to another desk.
+  </summary>
+</histogram>
+
+<histogram name="Ash.Desks.NumberOfWindowsOnDesk_12" units="units"
+    expires_after="2023-04-23">
+  <owner>dandersson@chromium.org</owner>
+  <owner>janetmac@chromium.org</owner>
+  <summary>
+    The number of windows on the twelfth desk. Emitted when a desk is removed,
+    or a window is moved to another desk.
+  </summary>
+</histogram>
+
+<histogram name="Ash.Desks.NumberOfWindowsOnDesk_13" units="units"
+    expires_after="2023-04-23">
+  <owner>dandersson@chromium.org</owner>
+  <owner>janetmac@chromium.org</owner>
+  <summary>
+    The number of windows on the thirteenth desk. Emitted when a desk is
+    removed, or a window is moved to another desk.
+  </summary>
+</histogram>
+
+<histogram name="Ash.Desks.NumberOfWindowsOnDesk_14" units="units"
+    expires_after="2023-04-23">
+  <owner>dandersson@chromium.org</owner>
+  <owner>janetmac@chromium.org</owner>
+  <summary>
+    The number of windows on the fourteenth desk. Emitted when a desk is
+    removed, or a window is moved to another desk.
+  </summary>
+</histogram>
+
+<histogram name="Ash.Desks.NumberOfWindowsOnDesk_15" units="units"
+    expires_after="2023-04-23">
+  <owner>dandersson@chromium.org</owner>
+  <owner>janetmac@chromium.org</owner>
+  <summary>
+    The number of windows on the fifteenth desk. Emitted when a desk is removed,
+    or a window is moved to another desk.
+  </summary>
+</histogram>
+
+<histogram name="Ash.Desks.NumberOfWindowsOnDesk_16" units="units"
+    expires_after="2023-04-23">
+  <owner>dandersson@chromium.org</owner>
+  <owner>janetmac@chromium.org</owner>
+  <summary>
+    The number of windows on the sixteenth desk. Emitted when a desk is removed,
+    or a window is moved to another desk.
+  </summary>
+</histogram>
+
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_2" units="units"
     expires_after="2023-04-23">
   <owner>afakhry@chromium.org</owner>
@@ -1714,6 +1784,16 @@
   </summary>
 </histogram>
 
+<histogram name="Ash.Desks.NumberOfWindowsOnDesk_9" units="units"
+    expires_after="2023-04-23">
+  <owner>dandersson@chromium.org</owner>
+  <owner>janetmac@chromium.org</owner>
+  <summary>
+    The number of windows on the ninth desk. Emitted when a desk is removed, or
+    a window is moved to another desk.
+  </summary>
+</histogram>
+
 <histogram name="Ash.Desks.PresentationTime.UpdateGesture" units="ms"
     expires_after="2023-01-10">
   <owner>afakhry@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/autofill/histograms.xml b/tools/metrics/histograms/metadata/autofill/histograms.xml
index 3f314a1..8a93992 100644
--- a/tools/metrics/histograms/metadata/autofill/histograms.xml
+++ b/tools/metrics/histograms/metadata/autofill/histograms.xml
@@ -280,18 +280,6 @@
   <token key="Group" variants="Autofill.Ablation.Group"/>
 </histogram>
 
-<histogram
-    name="Autofill.AcceptedFilledFieldWithNumericQuantityHeuristicPrediction"
-    enum="Boolean" expires_after="M112">
-  <owner>koerber@google.com</owner>
-  <owner>chrome-autofill-alerts@google.com</owner>
-  <summary>
-    Logs if the filling of a field was accepted even though it had a
-    NUMERIC_QUANTITY prediction. This metric is only emitted if the feature to
-    grant the heuristic precedence is disabled. Emitted on submission time.
-  </summary>
-</histogram>
-
 <histogram name="Autofill.Address.IsEnabled.PageLoad" enum="BooleanEnabled"
     expires_after="2023-02-12">
   <owner>jsaul@google.com</owner>
@@ -2292,16 +2280,6 @@
   </summary>
 </histogram>
 
-<histogram name="Autofill.NumericQuantityCollidesWithServerPrediction"
-    enum="Boolean" expires_after="M112">
-  <owner>koerber@google.com</owner>
-  <owner>chrome-autofill-alerts@google.com</owner>
-  <summary>
-    Logs that a field with a heuristic prediction for an NUMERIC_QUANTITY
-    collides with a server prediction. The metric is emitted on form submission.
-  </summary>
-</histogram>
-
 <histogram name="Autofill.Offer.SelectedCardHasOffer"
     enum="AutofillCreditCardOfferSelection" expires_after="2023-08-01">
   <owner>siyua@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
index 237115c..60bee55 100644
--- a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
+++ b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
@@ -469,7 +469,7 @@
 </histogram>
 
 <histogram name="CustomTabs.ShareOptionLocation" enum="ShareOptionLocation"
-    expires_after="M109">
+    expires_after="M115">
   <owner>sophey@chromium.org</owner>
   <owner>src/components/send_tab_to_self/OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/download/histograms.xml b/tools/metrics/histograms/metadata/download/histograms.xml
index 80f6834..7dee014 100644
--- a/tools/metrics/histograms/metadata/download/histograms.xml
+++ b/tools/metrics/histograms/metadata/download/histograms.xml
@@ -1494,9 +1494,9 @@
 </histogram>
 
 <histogram name="Download.WinFileMoveError" enum="WinIFileOperationError"
-    expires_after="2020-07-31">
-  <owner>dtrainor@chromium.org</owner>
-  <owner>qinmin@chromium.org</owner>
+    expires_after="2023-10-12">
+  <owner>drubery@chromium.org</owner>
+  <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>Records the OS error code when moving a file on windows.</summary>
 </histogram>
 
diff --git a/tools/metrics/histograms/metadata/fingerprint/histograms.xml b/tools/metrics/histograms/metadata/fingerprint/histograms.xml
index e9fa5b29..491b6ac 100644
--- a/tools/metrics/histograms/metadata/fingerprint/histograms.xml
+++ b/tools/metrics/histograms/metadata/fingerprint/histograms.xml
@@ -154,9 +154,8 @@
 
 <histogram name="Fingerprint.Unlock.EnrolledFingerCount" units="count"
     expires_after="2023-04-05">
-  <owner>emaamari@google.com</owner>
-  <owner>jessejames@chromium.org</owner>
-  <owner>cros-lurs@google.com</owner>
+  <owner>tomhughes@chromium.org</owner>
+  <owner>chromeos-fingerprint@google.com</owner>
   <summary>Counts the number of fingers enrolled by the user.</summary>
 </histogram>
 
@@ -258,7 +257,7 @@
 </histogram>
 
 <histogram name="Fingerprint.UnlockEnabled" enum="BooleanEnabled"
-    expires_after="2023-02-12">
+    expires_after="2023-04-05">
   <owner>tomhughes@chromium.org</owner>
   <owner>chromeos-fingerprint@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/new_tab_page/histograms.xml b/tools/metrics/histograms/metadata/new_tab_page/histograms.xml
index 66b8c3ce..368638a5 100644
--- a/tools/metrics/histograms/metadata/new_tab_page/histograms.xml
+++ b/tools/metrics/histograms/metadata/new_tab_page/histograms.xml
@@ -204,7 +204,7 @@
 </histogram>
 
 <histogram name="NewTabPage.Carts.DiscountConsentStatusAtLoad.{ConsentState}"
-    enum="CartDiscountConsentVariation" expires_after="2022-08-21">
+    enum="CartDiscountConsentVariation" expires_after="2023-03-05">
   <owner>meiliang@chromium.org</owner>
   <owner>chrome-shopping@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/power/histograms.xml b/tools/metrics/histograms/metadata/power/histograms.xml
index c4795b3..91655b4e 100644
--- a/tools/metrics/histograms/metadata/power/histograms.xml
+++ b/tools/metrics/histograms/metadata/power/histograms.xml
@@ -146,19 +146,19 @@
                but there was in the last 2 minutes"/>
 </variants>
 
-<histogram name="PerformanceMonitor.AverageCPU7.Total{UsageScenario}"
+<histogram name="PerformanceMonitor.AverageCPU8.Total{UsageScenario}"
     units="1/100 %" expires_after="2022-11-30">
   <owner>fdoray@chromium.org</owner>
   <owner>pmonette@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
-    See definition of PerformanceClass.AverageCPU7.ProcessName. This is recorded
+    See definition of PerformanceClass.AverageCPU8.ProcessName. This is recorded
     every 2 minutes for {UsageScenario} (see go/chrome_power_use_per_scenario).
   </summary>
   <token key="UsageScenario" variants="UsageScenario"/>
 </histogram>
 
-<histogram name="PerformanceMonitor.AverageCPU7.{ProcessName}" units="1/100 %"
+<histogram name="PerformanceMonitor.AverageCPU8.{ProcessName}" units="1/100 %"
     expires_after="2022-11-30">
   <owner>fdoray@chromium.org</owner>
   <owner>pmonette@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/printing/histograms.xml b/tools/metrics/histograms/metadata/printing/histograms.xml
index 778a7650..32e5d282 100644
--- a/tools/metrics/histograms/metadata/printing/histograms.xml
+++ b/tools/metrics/histograms/metadata/printing/histograms.xml
@@ -203,20 +203,6 @@
   </summary>
 </histogram>
 
-<histogram name="Printing.CUPS.PrinterEditDialogActions"
-    enum="PrinterEditDialogActions" expires_after="2023-09-26">
-  <owner>nmuggli@google.com</owner>
-  <owner>project-bolton@google.com</owner>
-  <summary>
-    Tracks when the printer edit dialog is opened and certain user interactions.
-    Every time the dialog is opened, the first bucket will get incremented.
-    Additional buckets will get incremented for specific actions, such as
-    clicking the View PPD button. Therefore, the first bucket acts as the total
-    number of potential events and subsequest buckets track how many times
-    specific events occurred. Only on Chrome OS.
-  </summary>
-</histogram>
-
 <histogram name="Printing.CUPS.PrinterRemoved" enum="PrinterProtocol"
     expires_after="2023-02-26">
   <owner>bmgordon@chromium.org</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index c8a6861..756e1e7 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,8 +5,8 @@
             "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux_arm64/49b4b5dcbc312d8d2c3751cf29238b8efeb4e494/trace_processor_shell"
         },
         "win": {
-            "hash": "27e80ba16d9c6e2283f3f1cab33fa391db47f298",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/4fcf7d61f3559fdb37fefda36e272f05e40f0fef/trace_processor_shell.exe"
+            "hash": "d625ef60494ca567d77d0803c9765f8120530e16",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/750df6fbf0d2bb50332cf49e00bca15dca2e6735/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "58893933be305d3bfe0a72ebebcacde2ac3ca893",
@@ -21,8 +21,8 @@
             "full_remote_path": "perfetto-luci-artifacts/v25.0/mac-arm64/trace_processor_shell"
         },
         "linux": {
-            "hash": "6006cedac850c9f14c1e4ab18d032731afcde121",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/4fcf7d61f3559fdb37fefda36e272f05e40f0fef/trace_processor_shell"
+            "hash": "9d44d2f8ea3c5cc84da4a5a2c9296e9b80fd2fc4",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/750df6fbf0d2bb50332cf49e00bca15dca2e6735/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/typescript/definitions/chrome_test.d.ts b/tools/typescript/definitions/chrome_test.d.ts
index ca77066..5ff2c4a 100644
--- a/tools/typescript/definitions/chrome_test.d.ts
+++ b/tools/typescript/definitions/chrome_test.d.ts
@@ -12,7 +12,6 @@
     export function assertTrue(value: boolean, message?: string): asserts value;
     export function fail(message?: string): never;
     export function runTests(tests: Array<() => void>): void;
-    export function runWithUserGesture(callback: () => void): void;
     export function succeed(message?: string): void;
   }
 }
diff --git a/ui/file_manager/file_manager/foreground/js/ui/actions_submenu.js b/ui/file_manager/file_manager/foreground/js/ui/actions_submenu.js
index cf9b481..03fffd4b 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/actions_submenu.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/actions_submenu.js
@@ -113,11 +113,12 @@
     let hasCustomActions = false;
     // Process all the rest as custom actions.
     Object.keys(remainingActions).forEach(key => {
-      // Certain actions (e.g. 'pin-folder' to Directory tree) do not seem to
-      // have a title, and thus don't appear in the menu even though we add it
-      // to the DOM.
       const action = remainingActions[key];
-      hasCustomActions = hasCustomActions || !!action.getTitle();
+      // If the action has no title it isn't visible to users, so we skip here.
+      if (!action.getTitle()) {
+        return;
+      }
+      hasCustomActions = true;
       const options = {label: action.getTitle()};
       const menuItem = this.addMenuItem_(options);
 
diff --git a/ui/file_manager/integration_tests/file_manager/drive_specific.js b/ui/file_manager/integration_tests/file_manager/drive_specific.js
index 20f2cbd44..ef096842 100644
--- a/ui/file_manager/integration_tests/file_manager/drive_specific.js
+++ b/ui/file_manager/integration_tests/file_manager/drive_specific.js
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {ENTRIES, getCaller, pending, repeatUntil, RootPath, sendTestMessage, TestEntryInfo} from '../test_util.js';
+import {ENTRIES, EntryType, getCaller, pending, repeatUntil, RootPath, sendTestMessage, TestEntryInfo} from '../test_util.js';
 import {testcase} from '../testcase.js';
 
-import {isSinglePartitionFormat, navigateWithDirectoryTree, remoteCall, setupAndWaitUntilReady, waitForMediaApp} from './background.js';
+import {navigateWithDirectoryTree, remoteCall, setupAndWaitUntilReady, waitForMediaApp} from './background.js';
 import {BASIC_DRIVE_ENTRY_SET, FILE_MANAGER_EXTENSIONS_ID, OFFLINE_ENTRY_SET, SHARED_WITH_ME_ENTRY_SET} from './test_data.js';
 
 /**
@@ -889,6 +889,51 @@
 };
 
 /**
+ * Tests that the inline file sync icons are displayed in Drive as files
+ * start syncing.
+ */
+testcase.driveInlineSyncStatus = async () => {
+  const toBeUploaded = new TestEntryInfo({
+    type: EntryType.FILE,
+    sourceFileName: 'video.ogv',
+    thumbnailFileName: 'image.png',
+    targetPath: 'world.ogv',
+    mimeType: 'video/ogg',
+    lastModifiedTime: 'Jul 4, 2012, 10:35 AM',
+    nameText: 'world.ogv',
+    sizeText: '59 KB',
+    typeText: 'OGG video',
+    availableOffline: true,
+  });
+
+  // Open Files app on Drive and copy over entry to be uploaded.
+  const appId =
+      await setupAndWaitUntilReady(RootPath.DRIVE, [], [toBeUploaded]);
+
+  // Fake syncing the file to Drive.
+  await sendTestMessage({
+    name: 'setDriveFileSyncStatus',
+    path: `/root/${toBeUploaded.targetPath}`,
+    syncStatus: 'in_progress',
+  });
+
+  const syncStatusQuery = '[data-sync-status=in_progress]';
+
+  // Verify the "sync in progress" icon is displayed.
+  await remoteCall.waitForElement(appId, syncStatusQuery);
+
+  // Fake completing the file sync.
+  await sendTestMessage({
+    name: 'setDriveFileSyncStatus',
+    path: `/root/${toBeUploaded.targetPath}`,
+    syncStatus: 'completed',
+  });
+
+  // Verify the "sync in progress" icon is no longer displayed.
+  await remoteCall.waitForElementLost(appId, syncStatusQuery);
+};
+
+/**
  * Tests that the Enable Docs Offline dialog appears in the Files App.
  */
 testcase.driveEnableDocsOfflineDialog = async () => {
diff --git a/ui/file_manager/integration_tests/test_util.js b/ui/file_manager/integration_tests/test_util.js
index a62cb352..96810044 100644
--- a/ui/file_manager/integration_tests/test_util.js
+++ b/ui/file_manager/integration_tests/test_util.js
@@ -366,6 +366,8 @@
  *
  * pinned: Drive pinned status of this file. Defaults to false.
  *
+ * availableOffline: Whether the file is available offline. Defaults to false.
+ *
  * alternateUrl: File's Drive alternate URL. Defaults to an empty string.
  *
  * @typedef {{
@@ -383,6 +385,7 @@
  *    capabilities: (TestEntryCapabilities|undefined),
  *    folderFeature: (TestEntryFolderFeature|undefined),
  *    pinned: (boolean|undefined),
+ *    availableOffline: (boolean|undefined),
  *    alternateUrl: (string|undefined),
  * }}
  */
@@ -415,6 +418,7 @@
     this.capabilities = options.capabilities;
     this.folderFeature = options.folderFeature;
     this.pinned = !!options.pinned;
+    this.availableOffline = !!options.availableOffline;
     this.alternateUrl = options.alternateUrl || '';
     Object.freeze(this);
   }
diff --git a/ui/touch_selection/touch_selection_controller.cc b/ui/touch_selection/touch_selection_controller.cc
index f9cda36..8708a79 100644
--- a/ui/touch_selection/touch_selection_controller.cc
+++ b/ui/touch_selection/touch_selection_controller.cc
@@ -45,16 +45,6 @@
 
 }  // namespace
 
-TouchSelectionController::Config::Config()
-    : max_tap_duration(base::Milliseconds(300)),
-      tap_slop(8),
-      enable_adaptive_handle_orientation(false),
-      enable_longpress_drag_selection(false),
-      hide_active_handle(false) {}
-
-TouchSelectionController::Config::~Config() {
-}
-
 TouchSelectionController::TouchSelectionController(
     TouchSelectionControllerClient* client,
     const Config& config)
diff --git a/ui/touch_selection/touch_selection_controller.h b/ui/touch_selection/touch_selection_controller.h
index ba63705..5fdcf72 100644
--- a/ui/touch_selection/touch_selection_controller.h
+++ b/ui/touch_selection/touch_selection_controller.h
@@ -53,25 +53,22 @@
   };
 
   struct UI_TOUCH_SELECTION_EXPORT Config {
-    Config();
-    ~Config();
-
     // Maximum allowed time for handle tap detection. Defaults to 300 ms.
-    base::TimeDelta max_tap_duration;
+    base::TimeDelta max_tap_duration = base::Milliseconds(300);
 
     // Defaults to 8 DIPs.
-    float tap_slop;
+    float tap_slop = 8;
 
     // Controls whether adaptive orientation for selection handles is enabled.
     // Defaults to false.
-    bool enable_adaptive_handle_orientation;
+    bool enable_adaptive_handle_orientation = false;
 
     // Controls whether drag selection after a longpress is enabled.
     // Defaults to false.
-    bool enable_longpress_drag_selection;
+    bool enable_longpress_drag_selection = false;
 
     // Should we hide the active handle.
-    bool hide_active_handle;
+    bool hide_active_handle = false;
   };
 
   TouchSelectionController(TouchSelectionControllerClient* client,
diff --git a/ui/touch_selection/touch_selection_controller_unittest.cc b/ui/touch_selection/touch_selection_controller_unittest.cc
index 512a6af..a803840 100644
--- a/ui/touch_selection/touch_selection_controller_unittest.cc
+++ b/ui/touch_selection/touch_selection_controller_unittest.cc
@@ -19,9 +19,14 @@
 namespace ui {
 namespace {
 
-const int kDefaultTapTimeoutMs = 200;
-const float kDefaulTapSlop = 10.f;
-const gfx::PointF kIgnoredPoint(0, 0);
+constexpr int kDefaultTapTimeoutMs = 200;
+constexpr float kDefaultTapSlop = 10.f;
+constexpr gfx::PointF kIgnoredPoint(0, 0);
+
+constexpr TouchSelectionController::Config kDefaultConfig = {
+    .max_tap_duration = base::Milliseconds(kDefaultTapTimeoutMs),
+    .tap_slop = kDefaultTapSlop,
+};
 
 class MockTouchHandleDrawable : public TouchHandleDrawable {
  public:
@@ -48,18 +53,10 @@
   raw_ptr<bool> intersects_rect_;
 };
 
-}  // namespace
-
 class TouchSelectionControllerTest : public testing::Test,
                                      public TouchSelectionControllerClient {
  public:
-  TouchSelectionControllerTest()
-      : caret_moved_(false),
-        selection_moved_(false),
-        selection_points_swapped_(false),
-        needs_animate_(false),
-        animation_enabled_(true),
-        dragging_enabled_(false) {}
+  TouchSelectionControllerTest() = default;
 
   TouchSelectionControllerTest(const TouchSelectionControllerTest&) = delete;
   TouchSelectionControllerTest& operator=(const TouchSelectionControllerTest&) =
@@ -70,11 +67,8 @@
   // testing::Test implementation.
 
   void SetUp() override {
-    controller_ =
-        std::make_unique<TouchSelectionController>(this, DefaultConfig());
-    // Simulate start of a TouchEvent sequence.
-    controller_->WillHandleTouchEvent(
-        MockMotionEvent(MotionEvent::Action::DOWN));
+    InitializeControllerWithConfig(kDefaultConfig);
+    StartTouchEventSequence();
   }
 
   void TearDown() override { controller_.reset(); }
@@ -122,17 +116,11 @@
 
   void DidScroll() override {}
 
-  void EnableLongPressDragSelection() {
-    TouchSelectionController::Config config = DefaultConfig();
-    config.enable_longpress_drag_selection = true;
+  void InitializeControllerWithConfig(TouchSelectionController::Config config) {
     controller_ = std::make_unique<TouchSelectionController>(this, config);
   }
 
-  void SetHideActiveHandle(bool hide) {
-    TouchSelectionController::Config config = DefaultConfig();
-    config.hide_active_handle = hide;
-    controller_ = std::make_unique<TouchSelectionController>(this, config);
-    // Simulate start of a TouchEvent sequence.
+  void StartTouchEventSequence() {
     controller_->WillHandleTouchEvent(
         MockMotionEvent(MotionEvent::Action::DOWN));
   }
@@ -251,16 +239,6 @@
   TouchSelectionController& controller() { return *controller_; }
 
  private:
-  TouchSelectionController::Config DefaultConfig() {
-    // |enable_longpress_drag_selection| is set to false by default, and should
-    // be overriden for explicit testing.
-    TouchSelectionController::Config config;
-    config.max_tap_duration = base::Milliseconds(kDefaultTapTimeoutMs);
-    config.tap_slop = kDefaulTapSlop;
-    config.enable_longpress_drag_selection = false;
-    return config;
-  }
-
   gfx::PointF last_event_start_;
   gfx::PointF last_event_end_;
   gfx::PointF caret_position_;
@@ -269,12 +247,12 @@
   gfx::RectF last_event_bounds_rect_;
   gfx::PointF last_drag_update_position_;
   std::vector<SelectionEventType> events_;
-  bool caret_moved_;
-  bool selection_moved_;
-  bool selection_points_swapped_;
-  bool needs_animate_;
-  bool animation_enabled_;
-  bool dragging_enabled_;
+  bool caret_moved_ = false;
+  bool selection_moved_ = false;
+  bool selection_points_swapped_ = false;
+  bool needs_animate_ = false;
+  bool animation_enabled_ = true;
+  bool dragging_enabled_ = false;
   std::unique_ptr<TouchSelectionController> controller_;
 };
 
@@ -985,7 +963,9 @@
 }
 
 TEST_F(TouchSelectionControllerTest, LongPressDrag) {
-  EnableLongPressDragSelection();
+  TouchSelectionController::Config config = kDefaultConfig;
+  config.enable_longpress_drag_selection = true;
+  InitializeControllerWithConfig(config);
   TouchSelectionControllerTestApi test_controller(&controller());
 
   gfx::RectF start_rect(-50, 0, 0, 10);
@@ -1016,29 +996,29 @@
   EXPECT_TRUE(controller().WillHandleTouchEvent(event.MovePoint(0, 0, 0)));
   EXPECT_THAT(GetAndResetEvents(), IsEmpty());
 
-  EXPECT_TRUE(
-      controller().WillHandleTouchEvent(event.MovePoint(0, 0, kDefaulTapSlop)));
+  EXPECT_TRUE(controller().WillHandleTouchEvent(
+      event.MovePoint(0, 0, kDefaultTapSlop)));
   EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED));
   EXPECT_EQ(fixed_offset, GetLastSelectionStart());
   EXPECT_EQ(end_offset, GetLastSelectionEnd());
 
   // Movement after the start of drag will be relative to the moved endpoint.
   EXPECT_TRUE(controller().WillHandleTouchEvent(
-      event.MovePoint(0, 0, 2 * kDefaulTapSlop)));
+      event.MovePoint(0, 0, 2 * kDefaultTapSlop)));
   EXPECT_TRUE(GetAndResetSelectionMoved());
-  EXPECT_EQ(end_offset + gfx::Vector2dF(0, kDefaulTapSlop),
+  EXPECT_EQ(end_offset + gfx::Vector2dF(0, kDefaultTapSlop),
             GetLastSelectionEnd());
 
   EXPECT_TRUE(controller().WillHandleTouchEvent(
-      event.MovePoint(0, kDefaulTapSlop, 2 * kDefaulTapSlop)));
+      event.MovePoint(0, kDefaultTapSlop, 2 * kDefaultTapSlop)));
   EXPECT_TRUE(GetAndResetSelectionMoved());
-  EXPECT_EQ(end_offset + gfx::Vector2dF(kDefaulTapSlop, kDefaulTapSlop),
+  EXPECT_EQ(end_offset + gfx::Vector2dF(kDefaultTapSlop, kDefaultTapSlop),
             GetLastSelectionEnd());
 
   EXPECT_TRUE(controller().WillHandleTouchEvent(
-      event.MovePoint(0, 2 * kDefaulTapSlop, 2 * kDefaulTapSlop)));
+      event.MovePoint(0, 2 * kDefaultTapSlop, 2 * kDefaultTapSlop)));
   EXPECT_TRUE(GetAndResetSelectionMoved());
-  EXPECT_EQ(end_offset + gfx::Vector2dF(2 * kDefaulTapSlop, kDefaulTapSlop),
+  EXPECT_EQ(end_offset + gfx::Vector2dF(2 * kDefaultTapSlop, kDefaultTapSlop),
             GetLastSelectionEnd());
 
   // The handles should still be hidden.
@@ -1055,7 +1035,9 @@
 }
 
 TEST_F(TouchSelectionControllerTest, LongPressNoDrag) {
-  EnableLongPressDragSelection();
+  TouchSelectionController::Config config = kDefaultConfig;
+  config.enable_longpress_drag_selection = true;
+  InitializeControllerWithConfig(config);
   TouchSelectionControllerTestApi test_controller(&controller());
 
   gfx::RectF start_rect(-50, 0, 0, 10);
@@ -1091,6 +1073,7 @@
 
 TEST_F(TouchSelectionControllerTest, NoLongPressDragIfDisabled) {
   // The TouchSelectionController disables longpress drag selection by default.
+  InitializeControllerWithConfig(kDefaultConfig);
   TouchSelectionControllerTestApi test_controller(&controller());
 
   gfx::RectF start_rect(-50, 0, 0, 10);
@@ -1119,7 +1102,7 @@
   EXPECT_THAT(GetAndResetEvents(), IsEmpty());
 
   EXPECT_FALSE(controller().WillHandleTouchEvent(
-      event.MovePoint(0, 0, kDefaulTapSlop * 10)));
+      event.MovePoint(0, 0, kDefaultTapSlop * 10)));
   EXPECT_THAT(GetAndResetEvents(), IsEmpty());
 
   // Releasing the touch sequence should have no effect.
@@ -1518,8 +1501,10 @@
   EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED));
 }
 
-TEST_F(TouchSelectionControllerTest, LongpressDragSelectorUpdageDragPosition) {
-  EnableLongPressDragSelection();
+TEST_F(TouchSelectionControllerTest, LongpressDragSelectorUpdateDragPosition) {
+  TouchSelectionController::Config config = kDefaultConfig;
+  config.enable_longpress_drag_selection = true;
+  InitializeControllerWithConfig(config);
   float line_height = 10.f;
   gfx::RectF start_rect(-40, 0, 0, line_height);
   gfx::RectF end_rect(50, 0, 0, line_height);
@@ -1539,8 +1524,8 @@
   EXPECT_THAT(GetAndResetEvents(), IsEmpty());
 
   // Move within tap slop, move haven't started yet.
-  EXPECT_TRUE(
-      controller().WillHandleTouchEvent(event.MovePoint(0, 0, kDefaulTapSlop)));
+  EXPECT_TRUE(controller().WillHandleTouchEvent(
+      event.MovePoint(0, 0, kDefaultTapSlop)));
   EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED));
   EXPECT_EQ(gfx::PointF(0.f, 0.f), GetLastDragUpdatePosition());
 
@@ -1569,15 +1554,18 @@
 }
 
 TEST_F(TouchSelectionControllerTest, NoHideActiveInsertionHandle) {
-  SetHideActiveHandle(false);
+  TouchSelectionController::Config config = kDefaultConfig;
+  config.hide_active_handle = false;
+  InitializeControllerWithConfig(config);
   TouchSelectionControllerTestApi test_controller(&controller());
 
   base::TimeTicks event_time = base::TimeTicks::Now();
   float line_height = 10.f;
   gfx::RectF insertion_rect(10, 0, 0, line_height);
   bool visible = true;
-  OnTapEvent();
 
+  StartTouchEventSequence();
+  OnTapEvent();
   ChangeInsertion(insertion_rect, visible);
   EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_SHOWN));
 
@@ -1589,15 +1577,18 @@
 }
 
 TEST_F(TouchSelectionControllerTest, HideActiveInsertionHandle) {
-  SetHideActiveHandle(true);
+  TouchSelectionController::Config config = kDefaultConfig;
+  config.hide_active_handle = true;
+  InitializeControllerWithConfig(config);
   TouchSelectionControllerTestApi test_controller(&controller());
 
   base::TimeTicks event_time = base::TimeTicks::Now();
   float line_height = 10.f;
   gfx::RectF insertion_rect(10, 0, 0, line_height);
   bool visible = true;
-  OnTapEvent();
 
+  StartTouchEventSequence();
+  OnTapEvent();
   ChangeInsertion(insertion_rect, visible);
   EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_SHOWN));
 
@@ -1619,7 +1610,9 @@
 }
 
 TEST_F(TouchSelectionControllerTest, NoHideActiveSelectionHandle) {
-  SetHideActiveHandle(false);
+  TouchSelectionController::Config config = kDefaultConfig;
+  config.hide_active_handle = false;
+  InitializeControllerWithConfig(config);
   TouchSelectionControllerTestApi test_controller(&controller());
 
   base::TimeTicks event_time = base::TimeTicks::Now();
@@ -1627,8 +1620,9 @@
   gfx::RectF start_rect(10, 0, 0, line_height);
   gfx::RectF end_rect(50, 0, 0, line_height);
   bool visible = true;
-  OnLongPressEvent();
 
+  StartTouchEventSequence();
+  OnLongPressEvent();
   ChangeSelection(start_rect, visible, end_rect, visible);
 
   // Start handle.
@@ -1659,7 +1653,9 @@
 }
 
 TEST_F(TouchSelectionControllerTest, HideActiveSelectionHandle) {
-  SetHideActiveHandle(true);
+  TouchSelectionController::Config config = kDefaultConfig;
+  config.hide_active_handle = true;
+  InitializeControllerWithConfig(config);
   TouchSelectionControllerTestApi test_controller(&controller());
 
   base::TimeTicks event_time = base::TimeTicks::Now();
@@ -1667,8 +1663,9 @@
   gfx::RectF start_rect(10, 0, 0, line_height);
   gfx::RectF end_rect(50, 0, 0, line_height);
   bool visible = true;
-  OnLongPressEvent();
 
+  StartTouchEventSequence();
+  OnLongPressEvent();
   ChangeSelection(start_rect, visible, end_rect, visible);
 
   // Start handle.
@@ -1715,12 +1712,15 @@
 TEST_F(TouchSelectionControllerTest, SwipeToMoveCursor_HideHandlesIfShown) {
   // Step 1: Extra set-up.
   // For Android P+, we need to hide handles while showing magnifier.
-  SetHideActiveHandle(true);
+  TouchSelectionController::Config config = kDefaultConfig;
+  config.hide_active_handle = true;
+  InitializeControllerWithConfig(config);
   TouchSelectionControllerTestApi test_controller(&controller());
 
   gfx::RectF insertion_rect(5, 5, 0, 10);
   bool visible = true;
 
+  StartTouchEventSequence();
   OnTapEvent();
   ChangeInsertion(insertion_rect, visible);
   EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_SHOWN));
@@ -1745,12 +1745,15 @@
 TEST_F(TouchSelectionControllerTest, SwipeToMoveCursor_HandleWasNotShown) {
   // Step 1: Extra set-up.
   // For Android P+, we need to hide handles while showing magnifier.
-  SetHideActiveHandle(true);
+  TouchSelectionController::Config config = kDefaultConfig;
+  config.hide_active_handle = true;
+  InitializeControllerWithConfig(config);
   TouchSelectionControllerTestApi test_controller(&controller());
 
   gfx::RectF insertion_rect(5, 5, 0, 10);
   bool visible = true;
 
+  StartTouchEventSequence();
   OnTapEvent();
   ChangeInsertion(insertion_rect, visible);
   EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_SHOWN));
@@ -1779,4 +1782,5 @@
   EXPECT_TRUE(test_controller.GetStartVisible());
 }
 
+}  // namespace
 }  // namespace ui
diff --git a/ui/views/vector_icons/drag_general_selection.icon b/ui/views/vector_icons/drag_general_selection.icon
index 61b5044d..b1b5c37 100644
--- a/ui/views/vector_icons/drag_general_selection.icon
+++ b/ui/views/vector_icons/drag_general_selection.icon
@@ -3,87 +3,87 @@
 // found in the LICENSE file.
 
 CANVAS_DIMENSIONS, 20,
-MOVE_TO, 12.5f, 2.5f,
+MOVE_TO, 12.5f, 4.5f,
 R_H_LINE_TO, -1.67f,
-V_LINE_TO, 0.83f,
+V_LINE_TO, 2.83f,
 H_LINE_TO, 12.5f,
-V_LINE_TO, 2.5f,
+V_LINE_TO, 4.5f,
 CLOSE,
 R_MOVE_TO, 1.67f, 3.33f,
 R_H_LINE_TO, 1.67f,
-V_LINE_TO, 4.17f,
+V_LINE_TO, 6.17f,
 R_H_LINE_TO, -1.67f,
 R_V_LINE_TO, 1.67f,
 CLOSE,
 R_MOVE_TO, 0, 3.33f,
 R_H_LINE_TO, 1.67f,
-V_LINE_TO, 7.5f,
+V_LINE_TO, 9.5f,
 R_H_LINE_TO, -1.67f,
 R_V_LINE_TO, 1.67f,
 CLOSE,
-MOVE_TO, 7.5f, 15.83f,
-H_LINE_TO, 9.17f,
+MOVE_TO, 7.5f, 17.83f,
+R_H_LINE_TO, 1.67f,
 R_V_LINE_TO, -1.67f,
 H_LINE_TO, 7.5f,
 R_V_LINE_TO, 1.67f,
 CLOSE,
-MOVE_TO, 4.17f, 2.5f,
+MOVE_TO, 4.17f, 4.5f,
 R_H_LINE_TO, 1.67f,
-V_LINE_TO, 0.83f,
+V_LINE_TO, 2.83f,
 H_LINE_TO, 4.17f,
-V_LINE_TO, 2.5f,
+V_LINE_TO, 4.5f,
 CLOSE,
-MOVE_TO, 0.83f, 12.5f,
+R_MOVE_TO, -3.33f, 10,
 H_LINE_TO, 2.5f,
 R_V_LINE_TO, -1.67f,
 H_LINE_TO, 0.83f,
-R_V_LINE_TO, 1.67f,
+V_LINE_TO, 14.5f,
 CLOSE,
-R_MOVE_TO, 1.67f, 3.33f,
+MOVE_TO, 2.5f, 17.83f,
 R_V_LINE_TO, -1.67f,
 H_LINE_TO, 0.83f,
 R_CUBIC_TO, 0, 0.92f, 0.75f, 1.67f, 1.67f, 1.67f,
 CLOSE,
-MOVE_TO, 14.17f, 0.83f,
-V_LINE_TO, 2.5f,
+R_MOVE_TO, 11.67f, -15,
+V_LINE_TO, 4.5f,
 R_H_LINE_TO, 1.67f,
 R_CUBIC_TO, 0, -0.92f, -0.75f, -1.67f, -1.67f, -1.67f,
 CLOSE,
-MOVE_TO, 7.5f, 2.5f,
-H_LINE_TO, 9.17f,
-V_LINE_TO, 0.83f,
+MOVE_TO, 7.5f, 4.5f,
+R_H_LINE_TO, 1.67f,
+V_LINE_TO, 2.83f,
 H_LINE_TO, 7.5f,
-V_LINE_TO, 2.5f,
+V_LINE_TO, 4.5f,
 CLOSE,
-MOVE_TO, 0.83f, 5.83f,
+MOVE_TO, 0.83f, 7.83f,
 H_LINE_TO, 2.5f,
-V_LINE_TO, 4.17f,
+V_LINE_TO, 6.17f,
 H_LINE_TO, 0.83f,
 R_V_LINE_TO, 1.67f,
 CLOSE,
-MOVE_TO, 4.17f, 15.83f,
+R_MOVE_TO, 3.33f, 10,
 R_H_LINE_TO, 1.67f,
 R_V_LINE_TO, -1.67f,
 H_LINE_TO, 4.17f,
 R_V_LINE_TO, 1.67f,
 CLOSE,
-MOVE_TO, 0.83f, 9.17f,
+MOVE_TO, 0.83f, 11.17f,
 H_LINE_TO, 2.5f,
-V_LINE_TO, 7.5f,
+V_LINE_TO, 9.5f,
 H_LINE_TO, 0.83f,
 R_V_LINE_TO, 1.67f,
 CLOSE,
 R_MOVE_TO, 0, -6.67f,
 H_LINE_TO, 2.5f,
-V_LINE_TO, 0.83f,
+V_LINE_TO, 2.83f,
 R_CUBIC_TO, -0.92f, 0, -1.67f, 0.75f, -1.67f, 1.67f,
 CLOSE,
-MOVE_TO, 10.83f, 14.17f,
+MOVE_TO, 10.83f, 16.17f,
 R_V_LINE_TO, 1.67f,
 R_H_LINE_TO, 3.34f,
 R_LINE_TO, -0.01f, 3.33f,
 R_H_LINE_TO, 1.67f,
-R_LINE_TO, 0.01f, -3.33f,
+R_LINE_TO, 0.01f, -3.32f,
 R_LINE_TO, 3.33f, -0.01f,
 R_V_LINE_TO, -1.67f,
 R_LINE_TO, -3.33f, 0.01f,
@@ -91,5 +91,4 @@
 R_H_LINE_TO, -1.67f,
 R_V_LINE_TO, 3.33f,
 R_H_LINE_TO, -3.33f,
-CLOSE,
-NEW_PATH
+CLOSE
diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc
index 2b1429f..4e751b3 100644
--- a/ui/views/widget/native_widget_aura.cc
+++ b/ui/views/widget/native_widget_aura.cc
@@ -597,6 +597,9 @@
 }
 
 bool NativeWidgetAura::IsStackedAbove(gfx::NativeView native_view) {
+  if (!window_)
+    return false;
+
   // If the root windows are not shared between two native views
   // it is likely that they are child windows of different top level windows.
   // In that scenario, just check the top level windows.
diff --git a/ui/views/widget/native_widget_mac.mm b/ui/views/widget/native_widget_mac.mm
index 6f7fff2..50c4b63 100644
--- a/ui/views/widget/native_widget_mac.mm
+++ b/ui/views/widget/native_widget_mac.mm
@@ -550,6 +550,9 @@
 }
 
 bool NativeWidgetMac::IsStackedAbove(gfx::NativeView native_view) {
+  if (!GetNSWindowMojo())
+    return false;
+
   // -[NSApplication orderedWindows] are ordered front-to-back.
   NSWindow* first = GetNativeWindow().GetNativeNSWindow();
   NSWindow* second = [native_view.GetNativeNSView() window];
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc
index a29153a..8e2d497 100644
--- a/ui/views/widget/widget.cc
+++ b/ui/views/widget/widget.cc
@@ -321,6 +321,9 @@
 void Widget::Init(InitParams params) {
   TRACE_EVENT0("views", "Widget::Init");
 
+  DCHECK(!native_widget_initialized_)
+      << "This widget has already been initialized";
+
   if (params.name.empty() && params.delegate) {
     params.name = params.delegate->internal_name();
     // If an internal name was not provided the class name of the contents view
@@ -1342,10 +1345,16 @@
 // Widget, NativeWidgetDelegate implementation:
 
 bool Widget::IsModal() const {
+  if (!widget_delegate_)
+    return false;
+
   return widget_delegate_->GetModalType() != ui::MODAL_TYPE_NONE;
 }
 
 bool Widget::IsDialogBox() const {
+  if (!widget_delegate_)
+    return false;
+
   return !!widget_delegate_->AsDialogDelegate();
 }
 
diff --git a/ui/views/widget/widget_unittest.cc b/ui/views/widget/widget_unittest.cc
index f440d3cf..43d2c75 100644
--- a/ui/views/widget/widget_unittest.cc
+++ b/ui/views/widget/widget_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/callback.h"
 #include "base/memory/raw_ptr.h"
 #include "base/run_loop.h"
+#include "base/test/gtest_util.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -1059,6 +1060,15 @@
   widget()->Hide();
 }
 
+TEST_P(WidgetWithDestroyedNativeViewTest, Init) {
+  Widget::InitParams params;
+  EXPECT_DCHECK_DEATH(widget()->Init(std::move(params)));
+}
+
+TEST_P(WidgetWithDestroyedNativeViewTest, is_secondary_widget) {
+  widget()->is_secondary_widget();
+}
+
 TEST_P(WidgetWithDestroyedNativeViewTest, IsActive) {
   widget()->IsActive();
 }
@@ -1067,6 +1077,10 @@
   widget()->IsClosed();
 }
 
+TEST_P(WidgetWithDestroyedNativeViewTest, IsDialogBox) {
+  widget()->IsDialogBox();
+}
+
 TEST_P(WidgetWithDestroyedNativeViewTest, IsFullscreen) {
   widget()->IsFullscreen();
 }
@@ -1075,10 +1089,31 @@
   widget()->IsMaximized();
 }
 
+TEST_P(WidgetWithDestroyedNativeViewTest, IsMinimized) {
+  widget()->IsMinimized();
+}
+
+TEST_P(WidgetWithDestroyedNativeViewTest, IsModal) {
+  widget()->IsModal();
+}
+
 TEST_P(WidgetWithDestroyedNativeViewTest, IsMouseEventsEnabled) {
   widget()->IsMouseEventsEnabled();
 }
 
+TEST_P(WidgetWithDestroyedNativeViewTest, IsMoveLoopSupported) {
+  widget()->IsMoveLoopSupported();
+}
+
+TEST_P(WidgetWithDestroyedNativeViewTest, IsNativeWidgetInitialized) {
+  widget()->IsNativeWidgetInitialized();
+}
+
+TEST_P(WidgetWithDestroyedNativeViewTest, IsStackedAbove) {
+  std::unique_ptr<Widget> other_widget = CreateTestWidget();
+  widget()->IsStackedAbove(other_widget->GetNativeView());
+}
+
 TEST_P(WidgetWithDestroyedNativeViewTest, IsTranslucentWindowOpacitySupported) {
   widget()->IsTranslucentWindowOpacitySupported();
 }
@@ -1087,6 +1122,22 @@
   widget()->IsVisible();
 }
 
+TEST_P(WidgetWithDestroyedNativeViewTest, IsVisibleOnAllWorkspaces) {
+  widget()->IsVisibleOnAllWorkspaces();
+}
+
+TEST_P(WidgetWithDestroyedNativeViewTest, LayerTreeChanged) {
+  widget()->LayerTreeChanged();
+}
+
+TEST_P(WidgetWithDestroyedNativeViewTest, LayoutRootViewIfNecessary) {
+  widget()->LayoutRootViewIfNecessary();
+}
+
+TEST_P(WidgetWithDestroyedNativeViewTest, LockPaintAsActive) {
+  widget()->LockPaintAsActive();
+}
+
 TEST_P(WidgetWithDestroyedNativeViewTest, Maximize) {
   widget()->Maximize();
 }
@@ -1095,6 +1146,34 @@
   widget()->Minimize();
 }
 
+TEST_P(WidgetWithDestroyedNativeViewTest, movement_disabled) {
+  widget()->movement_disabled();
+}
+
+TEST_P(WidgetWithDestroyedNativeViewTest, native_widget_private) {
+  widget()->native_widget_private();
+}
+
+TEST_P(WidgetWithDestroyedNativeViewTest, native_widget) {
+  widget()->native_widget();
+}
+
+TEST_P(WidgetWithDestroyedNativeViewTest, non_client_view) {
+  widget()->non_client_view();
+}
+
+TEST_P(WidgetWithDestroyedNativeViewTest, NotifyNativeViewHierarchyChanged) {
+  widget()->NotifyNativeViewHierarchyChanged();
+}
+
+TEST_P(WidgetWithDestroyedNativeViewTest, NotifyNativeViewHierarchyWillChange) {
+  widget()->NotifyNativeViewHierarchyWillChange();
+}
+
+TEST_P(WidgetWithDestroyedNativeViewTest, NotifyWillRemoveView) {
+  widget()->NotifyWillRemoveView(widget()->non_client_view());
+}
+
 TEST_P(WidgetWithDestroyedNativeViewTest, ReleaseCapture) {
   widget()->ReleaseCapture();
 }